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