xref: /freebsd-src/contrib/llvm-project/clang/lib/Frontend/DependencyFile.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- DependencyFile.cpp - Generate dependency file --------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This code generates dependency files.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "clang/Frontend/Utils.h"
140b57cec5SDimitry Andric #include "clang/Basic/FileManager.h"
150b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
160b57cec5SDimitry Andric #include "clang/Frontend/DependencyOutputOptions.h"
170b57cec5SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
180b57cec5SDimitry Andric #include "clang/Lex/DirectoryLookup.h"
190b57cec5SDimitry Andric #include "clang/Lex/ModuleMap.h"
200b57cec5SDimitry Andric #include "clang/Lex/PPCallbacks.h"
210b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
220b57cec5SDimitry Andric #include "clang/Serialization/ASTReader.h"
230b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h"
240b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
250b57cec5SDimitry Andric #include "llvm/Support/Path.h"
260b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
27bdd1243dSDimitry Andric #include <optional>
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace clang;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric namespace {
320b57cec5SDimitry Andric struct DepCollectorPPCallbacks : public PPCallbacks {
330b57cec5SDimitry Andric   DependencyCollector &DepCollector;
3481ad6265SDimitry Andric   Preprocessor &PP;
3581ad6265SDimitry Andric   DepCollectorPPCallbacks(DependencyCollector &L, Preprocessor &PP)
3681ad6265SDimitry Andric       : DepCollector(L), PP(PP) {}
370b57cec5SDimitry Andric 
3881ad6265SDimitry Andric   void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
3981ad6265SDimitry Andric                         SrcMgr::CharacteristicKind FileType, FileID PrevFID,
4081ad6265SDimitry Andric                         SourceLocation Loc) override {
4181ad6265SDimitry Andric     if (Reason != PPCallbacks::LexedFileChangeReason::EnterFile)
420b57cec5SDimitry Andric       return;
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric     // Dependency generation really does want to go all the way to the
450b57cec5SDimitry Andric     // file entry for a source location to find out what is depended on.
460b57cec5SDimitry Andric     // We do not want #line markers to affect dependency generation!
47bdd1243dSDimitry Andric     if (std::optional<StringRef> Filename =
4881ad6265SDimitry Andric             PP.getSourceManager().getNonBuiltinFilenameForID(FID))
49e8d8bef9SDimitry Andric       DepCollector.maybeAddDependency(
50e8d8bef9SDimitry Andric           llvm::sys::path::remove_leading_dotslash(*Filename),
51e8d8bef9SDimitry Andric           /*FromModule*/ false, isSystem(FileType), /*IsModuleFile*/ false,
52e8d8bef9SDimitry Andric           /*IsMissing*/ false);
530b57cec5SDimitry Andric   }
540b57cec5SDimitry Andric 
55a7dea167SDimitry Andric   void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
560b57cec5SDimitry Andric                    SrcMgr::CharacteristicKind FileType) override {
570b57cec5SDimitry Andric     StringRef Filename =
580b57cec5SDimitry Andric         llvm::sys::path::remove_leading_dotslash(SkippedFile.getName());
595c16e71dSDimitry Andric     DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
600b57cec5SDimitry Andric                                     /*IsSystem=*/isSystem(FileType),
610b57cec5SDimitry Andric                                     /*IsModuleFile=*/false,
620b57cec5SDimitry Andric                                     /*IsMissing=*/false);
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric 
65*0fca6ea1SDimitry Andric   void EmbedDirective(SourceLocation, StringRef, bool,
66*0fca6ea1SDimitry Andric                       OptionalFileEntryRef File,
67*0fca6ea1SDimitry Andric                       const LexEmbedParametersResult &) override {
68*0fca6ea1SDimitry Andric     assert(File && "expected to only be called when the file is found");
69*0fca6ea1SDimitry Andric     StringRef FileName =
70*0fca6ea1SDimitry Andric         llvm::sys::path::remove_leading_dotslash(File->getName());
71*0fca6ea1SDimitry Andric     DepCollector.maybeAddDependency(FileName,
72*0fca6ea1SDimitry Andric                                     /*FromModule*/ false,
73*0fca6ea1SDimitry Andric                                     /*IsSystem*/ false,
74*0fca6ea1SDimitry Andric                                     /*IsModuleFile*/ false,
75*0fca6ea1SDimitry Andric                                     /*IsMissing*/ false);
76*0fca6ea1SDimitry Andric   }
77*0fca6ea1SDimitry Andric 
780b57cec5SDimitry Andric   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
790b57cec5SDimitry Andric                           StringRef FileName, bool IsAngled,
8081ad6265SDimitry Andric                           CharSourceRange FilenameRange,
81bdd1243dSDimitry Andric                           OptionalFileEntryRef File, StringRef SearchPath,
82*0fca6ea1SDimitry Andric                           StringRef RelativePath, const Module *SuggestedModule,
83*0fca6ea1SDimitry Andric                           bool ModuleImported,
840b57cec5SDimitry Andric                           SrcMgr::CharacteristicKind FileType) override {
850b57cec5SDimitry Andric     if (!File)
865c16e71dSDimitry Andric       DepCollector.maybeAddDependency(FileName, /*FromModule*/ false,
8706c3fb27SDimitry Andric                                       /*IsSystem*/ false,
8806c3fb27SDimitry Andric                                       /*IsModuleFile*/ false,
890b57cec5SDimitry Andric                                       /*IsMissing*/ true);
900b57cec5SDimitry Andric     // Files that actually exist are handled by FileChanged.
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric 
93*0fca6ea1SDimitry Andric   void HasEmbed(SourceLocation, StringRef, bool,
94*0fca6ea1SDimitry Andric                 OptionalFileEntryRef File) override {
95*0fca6ea1SDimitry Andric     if (!File)
96*0fca6ea1SDimitry Andric       return;
97*0fca6ea1SDimitry Andric     StringRef Filename =
98*0fca6ea1SDimitry Andric         llvm::sys::path::remove_leading_dotslash(File->getName());
99*0fca6ea1SDimitry Andric     DepCollector.maybeAddDependency(Filename,
100*0fca6ea1SDimitry Andric                                     /*FromModule=*/false, false,
101*0fca6ea1SDimitry Andric                                     /*IsModuleFile=*/false,
102*0fca6ea1SDimitry Andric                                     /*IsMissing=*/false);
103*0fca6ea1SDimitry Andric   }
104*0fca6ea1SDimitry Andric 
1050b57cec5SDimitry Andric   void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
106bdd1243dSDimitry Andric                   OptionalFileEntryRef File,
1070b57cec5SDimitry Andric                   SrcMgr::CharacteristicKind FileType) override {
1080b57cec5SDimitry Andric     if (!File)
1090b57cec5SDimitry Andric       return;
1100b57cec5SDimitry Andric     StringRef Filename =
1110b57cec5SDimitry Andric         llvm::sys::path::remove_leading_dotslash(File->getName());
1125c16e71dSDimitry Andric     DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
1130b57cec5SDimitry Andric                                     /*IsSystem=*/isSystem(FileType),
1140b57cec5SDimitry Andric                                     /*IsModuleFile=*/false,
1150b57cec5SDimitry Andric                                     /*IsMissing=*/false);
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric 
11881ad6265SDimitry Andric   void EndOfMainFile() override {
11981ad6265SDimitry Andric     DepCollector.finishedMainFile(PP.getDiagnostics());
12081ad6265SDimitry Andric   }
1210b57cec5SDimitry Andric };
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric struct DepCollectorMMCallbacks : public ModuleMapCallbacks {
1240b57cec5SDimitry Andric   DependencyCollector &DepCollector;
1250b57cec5SDimitry Andric   DepCollectorMMCallbacks(DependencyCollector &DC) : DepCollector(DC) {}
1260b57cec5SDimitry Andric 
1275f757f3fSDimitry Andric   void moduleMapFileRead(SourceLocation Loc, FileEntryRef Entry,
1280b57cec5SDimitry Andric                          bool IsSystem) override {
1290b57cec5SDimitry Andric     StringRef Filename = Entry.getName();
1305c16e71dSDimitry Andric     DepCollector.maybeAddDependency(Filename, /*FromModule*/ false,
1310b57cec5SDimitry Andric                                     /*IsSystem*/ IsSystem,
1320b57cec5SDimitry Andric                                     /*IsModuleFile*/ false,
1330b57cec5SDimitry Andric                                     /*IsMissing*/ false);
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric };
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric struct DepCollectorASTListener : public ASTReaderListener {
1380b57cec5SDimitry Andric   DependencyCollector &DepCollector;
139bdd1243dSDimitry Andric   FileManager &FileMgr;
140bdd1243dSDimitry Andric   DepCollectorASTListener(DependencyCollector &L, FileManager &FileMgr)
141bdd1243dSDimitry Andric       : DepCollector(L), FileMgr(FileMgr) {}
1420b57cec5SDimitry Andric   bool needsInputFileVisitation() override { return true; }
1430b57cec5SDimitry Andric   bool needsSystemInputFileVisitation() override {
1440b57cec5SDimitry Andric     return DepCollector.needSystemDependencies();
1450b57cec5SDimitry Andric   }
1460b57cec5SDimitry Andric   void visitModuleFile(StringRef Filename,
1470b57cec5SDimitry Andric                        serialization::ModuleKind Kind) override {
1485c16e71dSDimitry Andric     DepCollector.maybeAddDependency(Filename, /*FromModule*/ true,
1490b57cec5SDimitry Andric                                     /*IsSystem*/ false, /*IsModuleFile*/ true,
1500b57cec5SDimitry Andric                                     /*IsMissing*/ false);
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric   bool visitInputFile(StringRef Filename, bool IsSystem,
1530b57cec5SDimitry Andric                       bool IsOverridden, bool IsExplicitModule) override {
1540b57cec5SDimitry Andric     if (IsOverridden || IsExplicitModule)
1550b57cec5SDimitry Andric       return true;
1560b57cec5SDimitry Andric 
157bdd1243dSDimitry Andric     // Run this through the FileManager in order to respect 'use-external-name'
158bdd1243dSDimitry Andric     // in case we have a VFS overlay.
159bdd1243dSDimitry Andric     if (auto FE = FileMgr.getOptionalFileRef(Filename))
160bdd1243dSDimitry Andric       Filename = FE->getName();
161bdd1243dSDimitry Andric 
1620b57cec5SDimitry Andric     DepCollector.maybeAddDependency(Filename, /*FromModule*/ true, IsSystem,
1635c16e71dSDimitry Andric                                     /*IsModuleFile*/ false,
16406c3fb27SDimitry Andric                                     /*IsMissing*/ false);
1650b57cec5SDimitry Andric     return true;
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric };
1680b57cec5SDimitry Andric } // end anonymous namespace
1690b57cec5SDimitry Andric 
1705ffd83dbSDimitry Andric void DependencyCollector::maybeAddDependency(StringRef Filename,
1715ffd83dbSDimitry Andric                                              bool FromModule, bool IsSystem,
1725ffd83dbSDimitry Andric                                              bool IsModuleFile,
1730b57cec5SDimitry Andric                                              bool IsMissing) {
1745c16e71dSDimitry Andric   if (sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
1750b57cec5SDimitry Andric     addDependency(Filename);
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric bool DependencyCollector::addDependency(StringRef Filename) {
179fe6060f1SDimitry Andric   StringRef SearchPath;
180fe6060f1SDimitry Andric #ifdef _WIN32
181fe6060f1SDimitry Andric   // Make the search insensitive to case and separators.
182fe6060f1SDimitry Andric   llvm::SmallString<256> TmpPath = Filename;
183fe6060f1SDimitry Andric   llvm::sys::path::native(TmpPath);
184fe6060f1SDimitry Andric   std::transform(TmpPath.begin(), TmpPath.end(), TmpPath.begin(), ::tolower);
185fe6060f1SDimitry Andric   SearchPath = TmpPath.str();
186fe6060f1SDimitry Andric #else
187fe6060f1SDimitry Andric   SearchPath = Filename;
188fe6060f1SDimitry Andric #endif
189fe6060f1SDimitry Andric 
190fe6060f1SDimitry Andric   if (Seen.insert(SearchPath).second) {
1915ffd83dbSDimitry Andric     Dependencies.push_back(std::string(Filename));
1920b57cec5SDimitry Andric     return true;
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric   return false;
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric static bool isSpecialFilename(StringRef Filename) {
198bdd1243dSDimitry Andric   return Filename == "<built-in>";
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
2020b57cec5SDimitry Andric                                         bool IsSystem, bool IsModuleFile,
2030b57cec5SDimitry Andric                                         bool IsMissing) {
2040b57cec5SDimitry Andric   return !isSpecialFilename(Filename) &&
2050b57cec5SDimitry Andric          (needSystemDependencies() || !IsSystem);
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric DependencyCollector::~DependencyCollector() { }
2090b57cec5SDimitry Andric void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
21081ad6265SDimitry Andric   PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(*this, PP));
2110b57cec5SDimitry Andric   PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
212a7dea167SDimitry Andric       std::make_unique<DepCollectorMMCallbacks>(*this));
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric void DependencyCollector::attachToASTReader(ASTReader &R) {
215bdd1243dSDimitry Andric   R.addListener(
216bdd1243dSDimitry Andric       std::make_unique<DepCollectorASTListener>(*this, R.getFileManager()));
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric DependencyFileGenerator::DependencyFileGenerator(
2200b57cec5SDimitry Andric     const DependencyOutputOptions &Opts)
2210b57cec5SDimitry Andric     : OutputFile(Opts.OutputFile), Targets(Opts.Targets),
2220b57cec5SDimitry Andric       IncludeSystemHeaders(Opts.IncludeSystemHeaders),
2230b57cec5SDimitry Andric       PhonyTarget(Opts.UsePhonyTargets),
2240b57cec5SDimitry Andric       AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false),
2250b57cec5SDimitry Andric       IncludeModuleFiles(Opts.IncludeModuleFiles),
2260b57cec5SDimitry Andric       OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
2270b57cec5SDimitry Andric   for (const auto &ExtraDep : Opts.ExtraDeps) {
228fe6060f1SDimitry Andric     if (addDependency(ExtraDep.first))
2290b57cec5SDimitry Andric       ++InputFileIndex;
2300b57cec5SDimitry Andric   }
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) {
2340b57cec5SDimitry Andric   // Disable the "file not found" diagnostic if the -MG option was given.
2350b57cec5SDimitry Andric   if (AddMissingHeaderDeps)
2360b57cec5SDimitry Andric     PP.SetSuppressIncludeNotFoundError(true);
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   DependencyCollector::attachToPreprocessor(PP);
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric bool DependencyFileGenerator::sawDependency(StringRef Filename, bool FromModule,
2420b57cec5SDimitry Andric                                             bool IsSystem, bool IsModuleFile,
2430b57cec5SDimitry Andric                                             bool IsMissing) {
2440b57cec5SDimitry Andric   if (IsMissing) {
2450b57cec5SDimitry Andric     // Handle the case of missing file from an inclusion directive.
2460b57cec5SDimitry Andric     if (AddMissingHeaderDeps)
2470b57cec5SDimitry Andric       return true;
2480b57cec5SDimitry Andric     SeenMissingHeader = true;
2490b57cec5SDimitry Andric     return false;
2500b57cec5SDimitry Andric   }
2510b57cec5SDimitry Andric   if (IsModuleFile && !IncludeModuleFiles)
2520b57cec5SDimitry Andric     return false;
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   if (isSpecialFilename(Filename))
2550b57cec5SDimitry Andric     return false;
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   if (IncludeSystemHeaders)
2580b57cec5SDimitry Andric     return true;
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   return !IsSystem;
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric void DependencyFileGenerator::finishedMainFile(DiagnosticsEngine &Diags) {
2640b57cec5SDimitry Andric   outputDependencyFile(Diags);
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric /// Print the filename, with escaping or quoting that accommodates the three
2680b57cec5SDimitry Andric /// most likely tools that use dependency files: GNU Make, BSD Make, and
2690b57cec5SDimitry Andric /// NMake/Jom.
2700b57cec5SDimitry Andric ///
2710b57cec5SDimitry Andric /// BSD Make is the simplest case: It does no escaping at all.  This means
2720b57cec5SDimitry Andric /// characters that are normally delimiters, i.e. space and # (the comment
2730b57cec5SDimitry Andric /// character) simply aren't supported in filenames.
2740b57cec5SDimitry Andric ///
2750b57cec5SDimitry Andric /// GNU Make does allow space and # in filenames, but to avoid being treated
2760b57cec5SDimitry Andric /// as a delimiter or comment, these must be escaped with a backslash. Because
2770b57cec5SDimitry Andric /// backslash is itself the escape character, if a backslash appears in a
2780b57cec5SDimitry Andric /// filename, it should be escaped as well.  (As a special case, $ is escaped
2790b57cec5SDimitry Andric /// as $$, which is the normal Make way to handle the $ character.)
2800b57cec5SDimitry Andric /// For compatibility with BSD Make and historical practice, if GNU Make
2810b57cec5SDimitry Andric /// un-escapes characters in a filename but doesn't find a match, it will
2820b57cec5SDimitry Andric /// retry with the unmodified original string.
2830b57cec5SDimitry Andric ///
2840b57cec5SDimitry Andric /// GCC tries to accommodate both Make formats by escaping any space or #
2850b57cec5SDimitry Andric /// characters in the original filename, but not escaping backslashes.  The
2860b57cec5SDimitry Andric /// apparent intent is so that filenames with backslashes will be handled
2870b57cec5SDimitry Andric /// correctly by BSD Make, and by GNU Make in its fallback mode of using the
2880b57cec5SDimitry Andric /// unmodified original string; filenames with # or space characters aren't
2890b57cec5SDimitry Andric /// supported by BSD Make at all, but will be handled correctly by GNU Make
2900b57cec5SDimitry Andric /// due to the escaping.
2910b57cec5SDimitry Andric ///
2920b57cec5SDimitry Andric /// A corner case that GCC gets only partly right is when the original filename
2930b57cec5SDimitry Andric /// has a backslash immediately followed by space or #.  GNU Make would expect
2940b57cec5SDimitry Andric /// this backslash to be escaped; however GCC escapes the original backslash
2950b57cec5SDimitry Andric /// only when followed by space, not #.  It will therefore take a dependency
2960b57cec5SDimitry Andric /// from a directive such as
2970b57cec5SDimitry Andric ///     #include "a\ b\#c.h"
2980b57cec5SDimitry Andric /// and emit it as
2990b57cec5SDimitry Andric ///     a\\\ b\\#c.h
3000b57cec5SDimitry Andric /// which GNU Make will interpret as
3010b57cec5SDimitry Andric ///     a\ b\
3020b57cec5SDimitry Andric /// followed by a comment. Failing to find this file, it will fall back to the
3030b57cec5SDimitry Andric /// original string, which probably doesn't exist either; in any case it won't
3040b57cec5SDimitry Andric /// find
3050b57cec5SDimitry Andric ///     a\ b\#c.h
3060b57cec5SDimitry Andric /// which is the actual filename specified by the include directive.
3070b57cec5SDimitry Andric ///
3080b57cec5SDimitry Andric /// Clang does what GCC does, rather than what GNU Make expects.
3090b57cec5SDimitry Andric ///
3100b57cec5SDimitry Andric /// NMake/Jom has a different set of scary characters, but wraps filespecs in
3110b57cec5SDimitry Andric /// double-quotes to avoid misinterpreting them; see
3120b57cec5SDimitry Andric /// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
3130b57cec5SDimitry Andric /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
3140b57cec5SDimitry Andric /// for Windows file-naming info.
3150b57cec5SDimitry Andric static void PrintFilename(raw_ostream &OS, StringRef Filename,
3160b57cec5SDimitry Andric                           DependencyOutputFormat OutputFormat) {
3170b57cec5SDimitry Andric   // Convert filename to platform native path
3180b57cec5SDimitry Andric   llvm::SmallString<256> NativePath;
3190b57cec5SDimitry Andric   llvm::sys::path::native(Filename.str(), NativePath);
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric   if (OutputFormat == DependencyOutputFormat::NMake) {
3220b57cec5SDimitry Andric     // Add quotes if needed. These are the characters listed as "special" to
3230b57cec5SDimitry Andric     // NMake, that are legal in a Windows filespec, and that could cause
3240b57cec5SDimitry Andric     // misinterpretation of the dependency string.
3250b57cec5SDimitry Andric     if (NativePath.find_first_of(" #${}^!") != StringRef::npos)
3260b57cec5SDimitry Andric       OS << '\"' << NativePath << '\"';
3270b57cec5SDimitry Andric     else
3280b57cec5SDimitry Andric       OS << NativePath;
3290b57cec5SDimitry Andric     return;
3300b57cec5SDimitry Andric   }
3310b57cec5SDimitry Andric   assert(OutputFormat == DependencyOutputFormat::Make);
3320b57cec5SDimitry Andric   for (unsigned i = 0, e = NativePath.size(); i != e; ++i) {
3330b57cec5SDimitry Andric     if (NativePath[i] == '#') // Handle '#' the broken gcc way.
3340b57cec5SDimitry Andric       OS << '\\';
3350b57cec5SDimitry Andric     else if (NativePath[i] == ' ') { // Handle space correctly.
3360b57cec5SDimitry Andric       OS << '\\';
3370b57cec5SDimitry Andric       unsigned j = i;
3380b57cec5SDimitry Andric       while (j > 0 && NativePath[--j] == '\\')
3390b57cec5SDimitry Andric         OS << '\\';
3400b57cec5SDimitry Andric     } else if (NativePath[i] == '$') // $ is escaped by $$.
3410b57cec5SDimitry Andric       OS << '$';
3420b57cec5SDimitry Andric     OS << NativePath[i];
3430b57cec5SDimitry Andric   }
3440b57cec5SDimitry Andric }
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric void DependencyFileGenerator::outputDependencyFile(DiagnosticsEngine &Diags) {
3470b57cec5SDimitry Andric   if (SeenMissingHeader) {
3480b57cec5SDimitry Andric     llvm::sys::fs::remove(OutputFile);
3490b57cec5SDimitry Andric     return;
3500b57cec5SDimitry Andric   }
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric   std::error_code EC;
353fe6060f1SDimitry Andric   llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
3540b57cec5SDimitry Andric   if (EC) {
3550b57cec5SDimitry Andric     Diags.Report(diag::err_fe_error_opening) << OutputFile << EC.message();
3560b57cec5SDimitry Andric     return;
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   outputDependencyFile(OS);
3600b57cec5SDimitry Andric }
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
3630b57cec5SDimitry Andric   // Write out the dependency targets, trying to avoid overly long
3640b57cec5SDimitry Andric   // lines when possible. We try our best to emit exactly the same
365bdd1243dSDimitry Andric   // dependency file as GCC>=10, assuming the included files are the
3660b57cec5SDimitry Andric   // same.
3670b57cec5SDimitry Andric   const unsigned MaxColumns = 75;
3680b57cec5SDimitry Andric   unsigned Columns = 0;
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric   for (StringRef Target : Targets) {
3710b57cec5SDimitry Andric     unsigned N = Target.size();
3720b57cec5SDimitry Andric     if (Columns == 0) {
3730b57cec5SDimitry Andric       Columns += N;
3740b57cec5SDimitry Andric     } else if (Columns + N + 2 > MaxColumns) {
3750b57cec5SDimitry Andric       Columns = N + 2;
3760b57cec5SDimitry Andric       OS << " \\\n  ";
3770b57cec5SDimitry Andric     } else {
3780b57cec5SDimitry Andric       Columns += N + 1;
3790b57cec5SDimitry Andric       OS << ' ';
3800b57cec5SDimitry Andric     }
3810b57cec5SDimitry Andric     // Targets already quoted as needed.
3820b57cec5SDimitry Andric     OS << Target;
3830b57cec5SDimitry Andric   }
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   OS << ':';
3860b57cec5SDimitry Andric   Columns += 1;
3870b57cec5SDimitry Andric 
3880b57cec5SDimitry Andric   // Now add each dependency in the order it was seen, but avoiding
3890b57cec5SDimitry Andric   // duplicates.
3900b57cec5SDimitry Andric   ArrayRef<std::string> Files = getDependencies();
3910b57cec5SDimitry Andric   for (StringRef File : Files) {
392bdd1243dSDimitry Andric     if (File == "<stdin>")
393bdd1243dSDimitry Andric       continue;
3940b57cec5SDimitry Andric     // Start a new line if this would exceed the column limit. Make
3950b57cec5SDimitry Andric     // sure to leave space for a trailing " \" in case we need to
3960b57cec5SDimitry Andric     // break the line on the next iteration.
3970b57cec5SDimitry Andric     unsigned N = File.size();
3980b57cec5SDimitry Andric     if (Columns + (N + 1) + 2 > MaxColumns) {
3990b57cec5SDimitry Andric       OS << " \\\n ";
4000b57cec5SDimitry Andric       Columns = 2;
4010b57cec5SDimitry Andric     }
4020b57cec5SDimitry Andric     OS << ' ';
4030b57cec5SDimitry Andric     PrintFilename(OS, File, OutputFormat);
4040b57cec5SDimitry Andric     Columns += N + 1;
4050b57cec5SDimitry Andric   }
4060b57cec5SDimitry Andric   OS << '\n';
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric   // Create phony targets if requested.
4090b57cec5SDimitry Andric   if (PhonyTarget && !Files.empty()) {
4100b57cec5SDimitry Andric     unsigned Index = 0;
4110b57cec5SDimitry Andric     for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
4120b57cec5SDimitry Andric       if (Index++ == InputFileIndex)
4130b57cec5SDimitry Andric         continue;
4140b57cec5SDimitry Andric       PrintFilename(OS, *I, OutputFormat);
4150b57cec5SDimitry Andric       OS << ":\n";
4160b57cec5SDimitry Andric     }
4170b57cec5SDimitry Andric   }
4180b57cec5SDimitry Andric }
419