xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Frontend/DependencyFile.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- DependencyFile.cpp - Generate dependency file --------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This code generates dependency files.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg 
137330f729Sjoerg #include "clang/Frontend/Utils.h"
147330f729Sjoerg #include "clang/Basic/FileManager.h"
157330f729Sjoerg #include "clang/Basic/SourceManager.h"
167330f729Sjoerg #include "clang/Frontend/DependencyOutputOptions.h"
177330f729Sjoerg #include "clang/Frontend/FrontendDiagnostic.h"
187330f729Sjoerg #include "clang/Lex/DirectoryLookup.h"
197330f729Sjoerg #include "clang/Lex/ModuleMap.h"
207330f729Sjoerg #include "clang/Lex/PPCallbacks.h"
217330f729Sjoerg #include "clang/Lex/Preprocessor.h"
227330f729Sjoerg #include "clang/Serialization/ASTReader.h"
237330f729Sjoerg #include "llvm/ADT/StringSet.h"
247330f729Sjoerg #include "llvm/ADT/StringSwitch.h"
257330f729Sjoerg #include "llvm/Support/FileSystem.h"
267330f729Sjoerg #include "llvm/Support/Path.h"
277330f729Sjoerg #include "llvm/Support/raw_ostream.h"
287330f729Sjoerg 
297330f729Sjoerg using namespace clang;
307330f729Sjoerg 
317330f729Sjoerg namespace {
327330f729Sjoerg struct DepCollectorPPCallbacks : public PPCallbacks {
337330f729Sjoerg   DependencyCollector &DepCollector;
347330f729Sjoerg   SourceManager &SM;
357330f729Sjoerg   DiagnosticsEngine &Diags;
DepCollectorPPCallbacks__anon974771530111::DepCollectorPPCallbacks367330f729Sjoerg   DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM,
377330f729Sjoerg                           DiagnosticsEngine &Diags)
387330f729Sjoerg       : DepCollector(L), SM(SM), Diags(Diags) {}
397330f729Sjoerg 
FileChanged__anon974771530111::DepCollectorPPCallbacks407330f729Sjoerg   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
417330f729Sjoerg                    SrcMgr::CharacteristicKind FileType,
427330f729Sjoerg                    FileID PrevFID) override {
437330f729Sjoerg     if (Reason != PPCallbacks::EnterFile)
447330f729Sjoerg       return;
457330f729Sjoerg 
467330f729Sjoerg     // Dependency generation really does want to go all the way to the
477330f729Sjoerg     // file entry for a source location to find out what is depended on.
487330f729Sjoerg     // We do not want #line markers to affect dependency generation!
49*e038c9c4Sjoerg     if (Optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(
50*e038c9c4Sjoerg             SM.getFileID(SM.getExpansionLoc(Loc))))
51*e038c9c4Sjoerg       DepCollector.maybeAddDependency(
52*e038c9c4Sjoerg           llvm::sys::path::remove_leading_dotslash(*Filename),
53*e038c9c4Sjoerg           /*FromModule*/ false, isSystem(FileType), /*IsModuleFile*/ false,
54*e038c9c4Sjoerg           /*IsMissing*/ false);
557330f729Sjoerg   }
567330f729Sjoerg 
FileSkipped__anon974771530111::DepCollectorPPCallbacks577330f729Sjoerg   void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
587330f729Sjoerg                    SrcMgr::CharacteristicKind FileType) override {
597330f729Sjoerg     StringRef Filename =
607330f729Sjoerg         llvm::sys::path::remove_leading_dotslash(SkippedFile.getName());
617330f729Sjoerg     DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
627330f729Sjoerg                                     /*IsSystem=*/isSystem(FileType),
637330f729Sjoerg                                     /*IsModuleFile=*/false,
647330f729Sjoerg                                     /*IsMissing=*/false);
657330f729Sjoerg   }
667330f729Sjoerg 
InclusionDirective__anon974771530111::DepCollectorPPCallbacks677330f729Sjoerg   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
687330f729Sjoerg                           StringRef FileName, bool IsAngled,
697330f729Sjoerg                           CharSourceRange FilenameRange, const FileEntry *File,
707330f729Sjoerg                           StringRef SearchPath, StringRef RelativePath,
717330f729Sjoerg                           const Module *Imported,
727330f729Sjoerg                           SrcMgr::CharacteristicKind FileType) override {
737330f729Sjoerg     if (!File)
747330f729Sjoerg       DepCollector.maybeAddDependency(FileName, /*FromModule*/false,
757330f729Sjoerg                                      /*IsSystem*/false, /*IsModuleFile*/false,
767330f729Sjoerg                                      /*IsMissing*/true);
777330f729Sjoerg     // Files that actually exist are handled by FileChanged.
787330f729Sjoerg   }
797330f729Sjoerg 
HasInclude__anon974771530111::DepCollectorPPCallbacks807330f729Sjoerg   void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
817330f729Sjoerg                   Optional<FileEntryRef> File,
827330f729Sjoerg                   SrcMgr::CharacteristicKind FileType) override {
837330f729Sjoerg     if (!File)
847330f729Sjoerg       return;
857330f729Sjoerg     StringRef Filename =
867330f729Sjoerg         llvm::sys::path::remove_leading_dotslash(File->getName());
877330f729Sjoerg     DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
887330f729Sjoerg                                     /*IsSystem=*/isSystem(FileType),
897330f729Sjoerg                                     /*IsModuleFile=*/false,
907330f729Sjoerg                                     /*IsMissing=*/false);
917330f729Sjoerg   }
927330f729Sjoerg 
EndOfMainFile__anon974771530111::DepCollectorPPCallbacks937330f729Sjoerg   void EndOfMainFile() override { DepCollector.finishedMainFile(Diags); }
947330f729Sjoerg };
957330f729Sjoerg 
967330f729Sjoerg struct DepCollectorMMCallbacks : public ModuleMapCallbacks {
977330f729Sjoerg   DependencyCollector &DepCollector;
DepCollectorMMCallbacks__anon974771530111::DepCollectorMMCallbacks987330f729Sjoerg   DepCollectorMMCallbacks(DependencyCollector &DC) : DepCollector(DC) {}
997330f729Sjoerg 
moduleMapFileRead__anon974771530111::DepCollectorMMCallbacks1007330f729Sjoerg   void moduleMapFileRead(SourceLocation Loc, const FileEntry &Entry,
1017330f729Sjoerg                          bool IsSystem) override {
1027330f729Sjoerg     StringRef Filename = Entry.getName();
1037330f729Sjoerg     DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
1047330f729Sjoerg                                     /*IsSystem*/IsSystem,
1057330f729Sjoerg                                     /*IsModuleFile*/false,
1067330f729Sjoerg                                     /*IsMissing*/false);
1077330f729Sjoerg   }
1087330f729Sjoerg };
1097330f729Sjoerg 
1107330f729Sjoerg struct DepCollectorASTListener : public ASTReaderListener {
1117330f729Sjoerg   DependencyCollector &DepCollector;
DepCollectorASTListener__anon974771530111::DepCollectorASTListener1127330f729Sjoerg   DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
needsInputFileVisitation__anon974771530111::DepCollectorASTListener1137330f729Sjoerg   bool needsInputFileVisitation() override { return true; }
needsSystemInputFileVisitation__anon974771530111::DepCollectorASTListener1147330f729Sjoerg   bool needsSystemInputFileVisitation() override {
1157330f729Sjoerg     return DepCollector.needSystemDependencies();
1167330f729Sjoerg   }
visitModuleFile__anon974771530111::DepCollectorASTListener1177330f729Sjoerg   void visitModuleFile(StringRef Filename,
1187330f729Sjoerg                        serialization::ModuleKind Kind) override {
1197330f729Sjoerg     DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
1207330f729Sjoerg                                    /*IsSystem*/false, /*IsModuleFile*/true,
1217330f729Sjoerg                                    /*IsMissing*/false);
1227330f729Sjoerg   }
visitInputFile__anon974771530111::DepCollectorASTListener1237330f729Sjoerg   bool visitInputFile(StringRef Filename, bool IsSystem,
1247330f729Sjoerg                       bool IsOverridden, bool IsExplicitModule) override {
1257330f729Sjoerg     if (IsOverridden || IsExplicitModule)
1267330f729Sjoerg       return true;
1277330f729Sjoerg 
1287330f729Sjoerg     DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem,
1297330f729Sjoerg                                    /*IsModuleFile*/false, /*IsMissing*/false);
1307330f729Sjoerg     return true;
1317330f729Sjoerg   }
1327330f729Sjoerg };
1337330f729Sjoerg } // end anonymous namespace
1347330f729Sjoerg 
maybeAddDependency(StringRef Filename,bool FromModule,bool IsSystem,bool IsModuleFile,bool IsMissing)135*e038c9c4Sjoerg void DependencyCollector::maybeAddDependency(StringRef Filename,
136*e038c9c4Sjoerg                                              bool FromModule, bool IsSystem,
137*e038c9c4Sjoerg                                              bool IsModuleFile,
1387330f729Sjoerg                                              bool IsMissing) {
1397330f729Sjoerg   if (sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
1407330f729Sjoerg     addDependency(Filename);
1417330f729Sjoerg }
1427330f729Sjoerg 
addDependency(StringRef Filename)1437330f729Sjoerg bool DependencyCollector::addDependency(StringRef Filename) {
144*e038c9c4Sjoerg   StringRef SearchPath;
145*e038c9c4Sjoerg #ifdef _WIN32
146*e038c9c4Sjoerg   // Make the search insensitive to case and separators.
147*e038c9c4Sjoerg   llvm::SmallString<256> TmpPath = Filename;
148*e038c9c4Sjoerg   llvm::sys::path::native(TmpPath);
149*e038c9c4Sjoerg   std::transform(TmpPath.begin(), TmpPath.end(), TmpPath.begin(), ::tolower);
150*e038c9c4Sjoerg   SearchPath = TmpPath.str();
151*e038c9c4Sjoerg #else
152*e038c9c4Sjoerg   SearchPath = Filename;
153*e038c9c4Sjoerg #endif
154*e038c9c4Sjoerg 
155*e038c9c4Sjoerg   if (Seen.insert(SearchPath).second) {
156*e038c9c4Sjoerg     Dependencies.push_back(std::string(Filename));
1577330f729Sjoerg     return true;
1587330f729Sjoerg   }
1597330f729Sjoerg   return false;
1607330f729Sjoerg }
1617330f729Sjoerg 
isSpecialFilename(StringRef Filename)1627330f729Sjoerg static bool isSpecialFilename(StringRef Filename) {
1637330f729Sjoerg   return llvm::StringSwitch<bool>(Filename)
1647330f729Sjoerg       .Case("<built-in>", true)
1657330f729Sjoerg       .Case("<stdin>", true)
1667330f729Sjoerg       .Default(false);
1677330f729Sjoerg }
1687330f729Sjoerg 
sawDependency(StringRef Filename,bool FromModule,bool IsSystem,bool IsModuleFile,bool IsMissing)1697330f729Sjoerg bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
1707330f729Sjoerg                                         bool IsSystem, bool IsModuleFile,
1717330f729Sjoerg                                         bool IsMissing) {
1727330f729Sjoerg   return !isSpecialFilename(Filename) &&
1737330f729Sjoerg          (needSystemDependencies() || !IsSystem);
1747330f729Sjoerg }
1757330f729Sjoerg 
~DependencyCollector()1767330f729Sjoerg DependencyCollector::~DependencyCollector() { }
attachToPreprocessor(Preprocessor & PP)1777330f729Sjoerg void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
1787330f729Sjoerg   PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(
1797330f729Sjoerg       *this, PP.getSourceManager(), PP.getDiagnostics()));
1807330f729Sjoerg   PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
1817330f729Sjoerg       std::make_unique<DepCollectorMMCallbacks>(*this));
1827330f729Sjoerg }
attachToASTReader(ASTReader & R)1837330f729Sjoerg void DependencyCollector::attachToASTReader(ASTReader &R) {
1847330f729Sjoerg   R.addListener(std::make_unique<DepCollectorASTListener>(*this));
1857330f729Sjoerg }
1867330f729Sjoerg 
DependencyFileGenerator(const DependencyOutputOptions & Opts)1877330f729Sjoerg DependencyFileGenerator::DependencyFileGenerator(
1887330f729Sjoerg     const DependencyOutputOptions &Opts)
1897330f729Sjoerg     : OutputFile(Opts.OutputFile), Targets(Opts.Targets),
1907330f729Sjoerg       IncludeSystemHeaders(Opts.IncludeSystemHeaders),
1917330f729Sjoerg       PhonyTarget(Opts.UsePhonyTargets),
1927330f729Sjoerg       AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false),
1937330f729Sjoerg       IncludeModuleFiles(Opts.IncludeModuleFiles),
1947330f729Sjoerg       OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
1957330f729Sjoerg   for (const auto &ExtraDep : Opts.ExtraDeps) {
196*e038c9c4Sjoerg     if (addDependency(ExtraDep.first))
1977330f729Sjoerg       ++InputFileIndex;
1987330f729Sjoerg   }
1997330f729Sjoerg }
2007330f729Sjoerg 
attachToPreprocessor(Preprocessor & PP)2017330f729Sjoerg void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) {
2027330f729Sjoerg   // Disable the "file not found" diagnostic if the -MG option was given.
2037330f729Sjoerg   if (AddMissingHeaderDeps)
2047330f729Sjoerg     PP.SetSuppressIncludeNotFoundError(true);
2057330f729Sjoerg 
2067330f729Sjoerg   DependencyCollector::attachToPreprocessor(PP);
2077330f729Sjoerg }
2087330f729Sjoerg 
sawDependency(StringRef Filename,bool FromModule,bool IsSystem,bool IsModuleFile,bool IsMissing)2097330f729Sjoerg bool DependencyFileGenerator::sawDependency(StringRef Filename, bool FromModule,
2107330f729Sjoerg                                             bool IsSystem, bool IsModuleFile,
2117330f729Sjoerg                                             bool IsMissing) {
2127330f729Sjoerg   if (IsMissing) {
2137330f729Sjoerg     // Handle the case of missing file from an inclusion directive.
2147330f729Sjoerg     if (AddMissingHeaderDeps)
2157330f729Sjoerg       return true;
2167330f729Sjoerg     SeenMissingHeader = true;
2177330f729Sjoerg     return false;
2187330f729Sjoerg   }
2197330f729Sjoerg   if (IsModuleFile && !IncludeModuleFiles)
2207330f729Sjoerg     return false;
2217330f729Sjoerg 
2227330f729Sjoerg   if (isSpecialFilename(Filename))
2237330f729Sjoerg     return false;
2247330f729Sjoerg 
2257330f729Sjoerg   if (IncludeSystemHeaders)
2267330f729Sjoerg     return true;
2277330f729Sjoerg 
2287330f729Sjoerg   return !IsSystem;
2297330f729Sjoerg }
2307330f729Sjoerg 
finishedMainFile(DiagnosticsEngine & Diags)2317330f729Sjoerg void DependencyFileGenerator::finishedMainFile(DiagnosticsEngine &Diags) {
2327330f729Sjoerg   outputDependencyFile(Diags);
2337330f729Sjoerg }
2347330f729Sjoerg 
2357330f729Sjoerg /// Print the filename, with escaping or quoting that accommodates the three
2367330f729Sjoerg /// most likely tools that use dependency files: GNU Make, BSD Make, and
2377330f729Sjoerg /// NMake/Jom.
2387330f729Sjoerg ///
2397330f729Sjoerg /// BSD Make is the simplest case: It does no escaping at all.  This means
2407330f729Sjoerg /// characters that are normally delimiters, i.e. space and # (the comment
2417330f729Sjoerg /// character) simply aren't supported in filenames.
2427330f729Sjoerg ///
2437330f729Sjoerg /// GNU Make does allow space and # in filenames, but to avoid being treated
2447330f729Sjoerg /// as a delimiter or comment, these must be escaped with a backslash. Because
2457330f729Sjoerg /// backslash is itself the escape character, if a backslash appears in a
2467330f729Sjoerg /// filename, it should be escaped as well.  (As a special case, $ is escaped
2477330f729Sjoerg /// as $$, which is the normal Make way to handle the $ character.)
2487330f729Sjoerg /// For compatibility with BSD Make and historical practice, if GNU Make
2497330f729Sjoerg /// un-escapes characters in a filename but doesn't find a match, it will
2507330f729Sjoerg /// retry with the unmodified original string.
2517330f729Sjoerg ///
2527330f729Sjoerg /// GCC tries to accommodate both Make formats by escaping any space or #
2537330f729Sjoerg /// characters in the original filename, but not escaping backslashes.  The
2547330f729Sjoerg /// apparent intent is so that filenames with backslashes will be handled
2557330f729Sjoerg /// correctly by BSD Make, and by GNU Make in its fallback mode of using the
2567330f729Sjoerg /// unmodified original string; filenames with # or space characters aren't
2577330f729Sjoerg /// supported by BSD Make at all, but will be handled correctly by GNU Make
2587330f729Sjoerg /// due to the escaping.
2597330f729Sjoerg ///
2607330f729Sjoerg /// A corner case that GCC gets only partly right is when the original filename
2617330f729Sjoerg /// has a backslash immediately followed by space or #.  GNU Make would expect
2627330f729Sjoerg /// this backslash to be escaped; however GCC escapes the original backslash
2637330f729Sjoerg /// only when followed by space, not #.  It will therefore take a dependency
2647330f729Sjoerg /// from a directive such as
2657330f729Sjoerg ///     #include "a\ b\#c.h"
2667330f729Sjoerg /// and emit it as
2677330f729Sjoerg ///     a\\\ b\\#c.h
2687330f729Sjoerg /// which GNU Make will interpret as
2697330f729Sjoerg ///     a\ b\
2707330f729Sjoerg /// followed by a comment. Failing to find this file, it will fall back to the
2717330f729Sjoerg /// original string, which probably doesn't exist either; in any case it won't
2727330f729Sjoerg /// find
2737330f729Sjoerg ///     a\ b\#c.h
2747330f729Sjoerg /// which is the actual filename specified by the include directive.
2757330f729Sjoerg ///
2767330f729Sjoerg /// Clang does what GCC does, rather than what GNU Make expects.
2777330f729Sjoerg ///
2787330f729Sjoerg /// NMake/Jom has a different set of scary characters, but wraps filespecs in
2797330f729Sjoerg /// double-quotes to avoid misinterpreting them; see
2807330f729Sjoerg /// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
2817330f729Sjoerg /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
2827330f729Sjoerg /// for Windows file-naming info.
PrintFilename(raw_ostream & OS,StringRef Filename,DependencyOutputFormat OutputFormat)2837330f729Sjoerg static void PrintFilename(raw_ostream &OS, StringRef Filename,
2847330f729Sjoerg                           DependencyOutputFormat OutputFormat) {
2857330f729Sjoerg   // Convert filename to platform native path
2867330f729Sjoerg   llvm::SmallString<256> NativePath;
2877330f729Sjoerg   llvm::sys::path::native(Filename.str(), NativePath);
2887330f729Sjoerg 
2897330f729Sjoerg   if (OutputFormat == DependencyOutputFormat::NMake) {
2907330f729Sjoerg     // Add quotes if needed. These are the characters listed as "special" to
2917330f729Sjoerg     // NMake, that are legal in a Windows filespec, and that could cause
2927330f729Sjoerg     // misinterpretation of the dependency string.
2937330f729Sjoerg     if (NativePath.find_first_of(" #${}^!") != StringRef::npos)
2947330f729Sjoerg       OS << '\"' << NativePath << '\"';
2957330f729Sjoerg     else
2967330f729Sjoerg       OS << NativePath;
2977330f729Sjoerg     return;
2987330f729Sjoerg   }
2997330f729Sjoerg   assert(OutputFormat == DependencyOutputFormat::Make);
3007330f729Sjoerg   for (unsigned i = 0, e = NativePath.size(); i != e; ++i) {
3017330f729Sjoerg     if (NativePath[i] == '#') // Handle '#' the broken gcc way.
3027330f729Sjoerg       OS << '\\';
3037330f729Sjoerg     else if (NativePath[i] == ' ') { // Handle space correctly.
3047330f729Sjoerg       OS << '\\';
3057330f729Sjoerg       unsigned j = i;
3067330f729Sjoerg       while (j > 0 && NativePath[--j] == '\\')
3077330f729Sjoerg         OS << '\\';
3087330f729Sjoerg     } else if (NativePath[i] == '$') // $ is escaped by $$.
3097330f729Sjoerg       OS << '$';
3107330f729Sjoerg     OS << NativePath[i];
3117330f729Sjoerg   }
3127330f729Sjoerg }
3137330f729Sjoerg 
outputDependencyFile(DiagnosticsEngine & Diags)3147330f729Sjoerg void DependencyFileGenerator::outputDependencyFile(DiagnosticsEngine &Diags) {
3157330f729Sjoerg   if (SeenMissingHeader) {
3167330f729Sjoerg     llvm::sys::fs::remove(OutputFile);
3177330f729Sjoerg     return;
3187330f729Sjoerg   }
3197330f729Sjoerg 
3207330f729Sjoerg   std::error_code EC;
321*e038c9c4Sjoerg   llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
3227330f729Sjoerg   if (EC) {
3237330f729Sjoerg     Diags.Report(diag::err_fe_error_opening) << OutputFile << EC.message();
3247330f729Sjoerg     return;
3257330f729Sjoerg   }
3267330f729Sjoerg 
3277330f729Sjoerg   outputDependencyFile(OS);
3287330f729Sjoerg }
3297330f729Sjoerg 
outputDependencyFile(llvm::raw_ostream & OS)3307330f729Sjoerg void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
3317330f729Sjoerg   // Write out the dependency targets, trying to avoid overly long
3327330f729Sjoerg   // lines when possible. We try our best to emit exactly the same
3337330f729Sjoerg   // dependency file as GCC (4.2), assuming the included files are the
3347330f729Sjoerg   // same.
3357330f729Sjoerg   const unsigned MaxColumns = 75;
3367330f729Sjoerg   unsigned Columns = 0;
3377330f729Sjoerg 
3387330f729Sjoerg   for (StringRef Target : Targets) {
3397330f729Sjoerg     unsigned N = Target.size();
3407330f729Sjoerg     if (Columns == 0) {
3417330f729Sjoerg       Columns += N;
3427330f729Sjoerg     } else if (Columns + N + 2 > MaxColumns) {
3437330f729Sjoerg       Columns = N + 2;
3447330f729Sjoerg       OS << " \\\n  ";
3457330f729Sjoerg     } else {
3467330f729Sjoerg       Columns += N + 1;
3477330f729Sjoerg       OS << ' ';
3487330f729Sjoerg     }
3497330f729Sjoerg     // Targets already quoted as needed.
3507330f729Sjoerg     OS << Target;
3517330f729Sjoerg   }
3527330f729Sjoerg 
3537330f729Sjoerg   OS << ':';
3547330f729Sjoerg   Columns += 1;
3557330f729Sjoerg 
3567330f729Sjoerg   // Now add each dependency in the order it was seen, but avoiding
3577330f729Sjoerg   // duplicates.
3587330f729Sjoerg   ArrayRef<std::string> Files = getDependencies();
3597330f729Sjoerg   for (StringRef File : Files) {
3607330f729Sjoerg     // Start a new line if this would exceed the column limit. Make
3617330f729Sjoerg     // sure to leave space for a trailing " \" in case we need to
3627330f729Sjoerg     // break the line on the next iteration.
3637330f729Sjoerg     unsigned N = File.size();
3647330f729Sjoerg     if (Columns + (N + 1) + 2 > MaxColumns) {
3657330f729Sjoerg       OS << " \\\n ";
3667330f729Sjoerg       Columns = 2;
3677330f729Sjoerg     }
3687330f729Sjoerg     OS << ' ';
3697330f729Sjoerg     PrintFilename(OS, File, OutputFormat);
3707330f729Sjoerg     Columns += N + 1;
3717330f729Sjoerg   }
3727330f729Sjoerg   OS << '\n';
3737330f729Sjoerg 
3747330f729Sjoerg   // Create phony targets if requested.
3757330f729Sjoerg   if (PhonyTarget && !Files.empty()) {
3767330f729Sjoerg     unsigned Index = 0;
3777330f729Sjoerg     for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
3787330f729Sjoerg       if (Index++ == InputFileIndex)
3797330f729Sjoerg         continue;
3807330f729Sjoerg       OS << '\n';
3817330f729Sjoerg       PrintFilename(OS, *I, OutputFormat);
3827330f729Sjoerg       OS << ":\n";
3837330f729Sjoerg     }
3847330f729Sjoerg   }
3857330f729Sjoerg }
386