116b7b6f5SEli Friedman //===--- DependencyFile.cpp - Generate dependency file --------------------===//
216b7b6f5SEli Friedman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
616b7b6f5SEli Friedman //
716b7b6f5SEli Friedman //===----------------------------------------------------------------------===//
816b7b6f5SEli Friedman //
916b7b6f5SEli Friedman // This code generates dependency files.
1016b7b6f5SEli Friedman //
1116b7b6f5SEli Friedman //===----------------------------------------------------------------------===//
1216b7b6f5SEli Friedman
1316b7b6f5SEli Friedman #include "clang/Frontend/Utils.h"
1416b7b6f5SEli Friedman #include "clang/Basic/FileManager.h"
1589d1fdffSDaniel Dunbar #include "clang/Basic/SourceManager.h"
1689d1fdffSDaniel Dunbar #include "clang/Frontend/DependencyOutputOptions.h"
1789d1fdffSDaniel Dunbar #include "clang/Frontend/FrontendDiagnostic.h"
1889d1fdffSDaniel Dunbar #include "clang/Lex/DirectoryLookup.h"
192a6edb30SRichard Smith #include "clang/Lex/ModuleMap.h"
2089d1fdffSDaniel Dunbar #include "clang/Lex/PPCallbacks.h"
2189d1fdffSDaniel Dunbar #include "clang/Lex/Preprocessor.h"
22cb69b57bSBen Langmuir #include "clang/Serialization/ASTReader.h"
2316b7b6f5SEli Friedman #include "llvm/ADT/StringSet.h"
24f0822fb0SDavid Majnemer #include "llvm/ADT/StringSwitch.h"
2533d43303SBenjamin Kramer #include "llvm/Support/FileSystem.h"
26f7ca26a0SEli Friedman #include "llvm/Support/Path.h"
2716b7b6f5SEli Friedman #include "llvm/Support/raw_ostream.h"
2816b7b6f5SEli Friedman
2916b7b6f5SEli Friedman using namespace clang;
3016b7b6f5SEli Friedman
3116b7b6f5SEli Friedman namespace {
3233c8090aSBen Langmuir struct DepCollectorPPCallbacks : public PPCallbacks {
3333c8090aSBen Langmuir DependencyCollector &DepCollector;
34*0d3a2b4cSArgyrios Kyrtzidis Preprocessor &PP;
DepCollectorPPCallbacks__anonc25cc5380111::DepCollectorPPCallbacks35*0d3a2b4cSArgyrios Kyrtzidis DepCollectorPPCallbacks(DependencyCollector &L, Preprocessor &PP)
36*0d3a2b4cSArgyrios Kyrtzidis : DepCollector(L), PP(PP) {}
3733c8090aSBen Langmuir
LexedFileChanged__anonc25cc5380111::DepCollectorPPCallbacks38*0d3a2b4cSArgyrios Kyrtzidis void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
39*0d3a2b4cSArgyrios Kyrtzidis SrcMgr::CharacteristicKind FileType, FileID PrevFID,
40*0d3a2b4cSArgyrios Kyrtzidis SourceLocation Loc) override {
41*0d3a2b4cSArgyrios Kyrtzidis if (Reason != PPCallbacks::LexedFileChangeReason::EnterFile)
4233c8090aSBen Langmuir return;
4333c8090aSBen Langmuir
4433c8090aSBen Langmuir // Dependency generation really does want to go all the way to the
4533c8090aSBen Langmuir // file entry for a source location to find out what is depended on.
4633c8090aSBen Langmuir // We do not want #line markers to affect dependency generation!
47*0d3a2b4cSArgyrios Kyrtzidis if (Optional<StringRef> Filename =
48*0d3a2b4cSArgyrios Kyrtzidis PP.getSourceManager().getNonBuiltinFilenameForID(FID))
49cf593d22SDuncan P. N. Exon Smith DepCollector.maybeAddDependency(
50cf593d22SDuncan P. N. Exon Smith llvm::sys::path::remove_leading_dotslash(*Filename),
51cf593d22SDuncan P. N. Exon Smith /*FromModule*/ false, isSystem(FileType), /*IsModuleFile*/ false,
52cf593d22SDuncan P. N. Exon Smith /*IsMissing*/ false);
5333c8090aSBen Langmuir }
5433c8090aSBen Langmuir
FileSkipped__anonc25cc5380111::DepCollectorPPCallbacks5567d25fedSAlex Lorenz void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
568d9eb7acSAlex Lorenz SrcMgr::CharacteristicKind FileType) override {
578d9eb7acSAlex Lorenz StringRef Filename =
588d9eb7acSAlex Lorenz llvm::sys::path::remove_leading_dotslash(SkippedFile.getName());
598d9eb7acSAlex Lorenz DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
608d9eb7acSAlex Lorenz /*IsSystem=*/isSystem(FileType),
618d9eb7acSAlex Lorenz /*IsModuleFile=*/false,
628d9eb7acSAlex Lorenz /*IsMissing=*/false);
638d9eb7acSAlex Lorenz }
648d9eb7acSAlex Lorenz
InclusionDirective__anonc25cc5380111::DepCollectorPPCallbacks6533c8090aSBen Langmuir void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
6633c8090aSBen Langmuir StringRef FileName, bool IsAngled,
67d79ad2f1SJan Svoboda CharSourceRange FilenameRange,
68d79ad2f1SJan Svoboda Optional<FileEntryRef> File, StringRef SearchPath,
69d79ad2f1SJan Svoboda StringRef RelativePath, const Module *Imported,
7096fbe58bSJulie Hockett SrcMgr::CharacteristicKind FileType) override {
7133c8090aSBen Langmuir if (!File)
7233c8090aSBen Langmuir DepCollector.maybeAddDependency(FileName, /*FromModule*/false,
7333c8090aSBen Langmuir /*IsSystem*/false, /*IsModuleFile*/false,
7433c8090aSBen Langmuir /*IsMissing*/true);
7533c8090aSBen Langmuir // Files that actually exist are handled by FileChanged.
7633c8090aSBen Langmuir }
7733c8090aSBen Langmuir
HasInclude__anonc25cc5380111::DepCollectorPPCallbacks788d9eb7acSAlex Lorenz void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
791c8a4b72SAlex Lorenz Optional<FileEntryRef> File,
808d9eb7acSAlex Lorenz SrcMgr::CharacteristicKind FileType) override {
818d9eb7acSAlex Lorenz if (!File)
828d9eb7acSAlex Lorenz return;
838d9eb7acSAlex Lorenz StringRef Filename =
848d9eb7acSAlex Lorenz llvm::sys::path::remove_leading_dotslash(File->getName());
858d9eb7acSAlex Lorenz DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
868d9eb7acSAlex Lorenz /*IsSystem=*/isSystem(FileType),
878d9eb7acSAlex Lorenz /*IsModuleFile=*/false,
888d9eb7acSAlex Lorenz /*IsMissing=*/false);
8933c8090aSBen Langmuir }
908d9eb7acSAlex Lorenz
EndOfMainFile__anonc25cc5380111::DepCollectorPPCallbacks91*0d3a2b4cSArgyrios Kyrtzidis void EndOfMainFile() override {
92*0d3a2b4cSArgyrios Kyrtzidis DepCollector.finishedMainFile(PP.getDiagnostics());
93*0d3a2b4cSArgyrios Kyrtzidis }
9433c8090aSBen Langmuir };
9533c8090aSBen Langmuir
962a6edb30SRichard Smith struct DepCollectorMMCallbacks : public ModuleMapCallbacks {
972a6edb30SRichard Smith DependencyCollector &DepCollector;
DepCollectorMMCallbacks__anonc25cc5380111::DepCollectorMMCallbacks982a6edb30SRichard Smith DepCollectorMMCallbacks(DependencyCollector &DC) : DepCollector(DC) {}
992a6edb30SRichard Smith
moduleMapFileRead__anonc25cc5380111::DepCollectorMMCallbacks1002a6edb30SRichard Smith void moduleMapFileRead(SourceLocation Loc, const FileEntry &Entry,
1012a6edb30SRichard Smith bool IsSystem) override {
1022a6edb30SRichard Smith StringRef Filename = Entry.getName();
1032a6edb30SRichard Smith DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
1042a6edb30SRichard Smith /*IsSystem*/IsSystem,
1052a6edb30SRichard Smith /*IsModuleFile*/false,
1062a6edb30SRichard Smith /*IsMissing*/false);
1072a6edb30SRichard Smith }
1082a6edb30SRichard Smith };
1092a6edb30SRichard Smith
11033c8090aSBen Langmuir struct DepCollectorASTListener : public ASTReaderListener {
11133c8090aSBen Langmuir DependencyCollector &DepCollector;
DepCollectorASTListener__anonc25cc5380111::DepCollectorASTListener11233c8090aSBen Langmuir DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
needsInputFileVisitation__anonc25cc5380111::DepCollectorASTListener11333c8090aSBen Langmuir bool needsInputFileVisitation() override { return true; }
needsSystemInputFileVisitation__anonc25cc5380111::DepCollectorASTListener11433c8090aSBen Langmuir bool needsSystemInputFileVisitation() override {
11533c8090aSBen Langmuir return DepCollector.needSystemDependencies();
11633c8090aSBen Langmuir }
visitModuleFile__anonc25cc5380111::DepCollectorASTListener117216a3bd7SRichard Smith void visitModuleFile(StringRef Filename,
118216a3bd7SRichard Smith serialization::ModuleKind Kind) override {
11933c8090aSBen Langmuir DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
12033c8090aSBen Langmuir /*IsSystem*/false, /*IsModuleFile*/true,
12133c8090aSBen Langmuir /*IsMissing*/false);
12233c8090aSBen Langmuir }
visitInputFile__anonc25cc5380111::DepCollectorASTListener12333c8090aSBen Langmuir bool visitInputFile(StringRef Filename, bool IsSystem,
124216a3bd7SRichard Smith bool IsOverridden, bool IsExplicitModule) override {
125216a3bd7SRichard Smith if (IsOverridden || IsExplicitModule)
12633c8090aSBen Langmuir return true;
12733c8090aSBen Langmuir
12833c8090aSBen Langmuir DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem,
12933c8090aSBen Langmuir /*IsModuleFile*/false, /*IsMissing*/false);
13033c8090aSBen Langmuir return true;
13133c8090aSBen Langmuir }
13233c8090aSBen Langmuir };
13333c8090aSBen Langmuir } // end anonymous namespace
13433c8090aSBen Langmuir
maybeAddDependency(StringRef Filename,bool FromModule,bool IsSystem,bool IsModuleFile,bool IsMissing)135bcda1269SNico Weber void DependencyCollector::maybeAddDependency(StringRef Filename,
136bcda1269SNico Weber bool FromModule, bool IsSystem,
137bcda1269SNico Weber bool IsModuleFile,
13833c8090aSBen Langmuir bool IsMissing) {
1398d9eb7acSAlex Lorenz if (sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
1408d9eb7acSAlex Lorenz addDependency(Filename);
1418d9eb7acSAlex Lorenz }
1428d9eb7acSAlex Lorenz
addDependency(StringRef Filename)1438d9eb7acSAlex Lorenz bool DependencyCollector::addDependency(StringRef Filename) {
1446052a8a5SSylvain Audi StringRef SearchPath;
1456052a8a5SSylvain Audi #ifdef _WIN32
1466052a8a5SSylvain Audi // Make the search insensitive to case and separators.
1476052a8a5SSylvain Audi llvm::SmallString<256> TmpPath = Filename;
1486052a8a5SSylvain Audi llvm::sys::path::native(TmpPath);
1496052a8a5SSylvain Audi std::transform(TmpPath.begin(), TmpPath.end(), TmpPath.begin(), ::tolower);
1506052a8a5SSylvain Audi SearchPath = TmpPath.str();
1516052a8a5SSylvain Audi #else
1526052a8a5SSylvain Audi SearchPath = Filename;
1536052a8a5SSylvain Audi #endif
1546052a8a5SSylvain Audi
1556052a8a5SSylvain Audi if (Seen.insert(SearchPath).second) {
156adcd0268SBenjamin Kramer Dependencies.push_back(std::string(Filename));
1578d9eb7acSAlex Lorenz return true;
1588d9eb7acSAlex Lorenz }
1598d9eb7acSAlex Lorenz return false;
16033c8090aSBen Langmuir }
16133c8090aSBen Langmuir
isSpecialFilename(StringRef Filename)162f0822fb0SDavid Majnemer static bool isSpecialFilename(StringRef Filename) {
163f0822fb0SDavid Majnemer return llvm::StringSwitch<bool>(Filename)
164f0822fb0SDavid Majnemer .Case("<built-in>", true)
165f0822fb0SDavid Majnemer .Case("<stdin>", true)
166f0822fb0SDavid Majnemer .Default(false);
167f0822fb0SDavid Majnemer }
168f0822fb0SDavid Majnemer
sawDependency(StringRef Filename,bool FromModule,bool IsSystem,bool IsModuleFile,bool IsMissing)16933c8090aSBen Langmuir bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
17033c8090aSBen Langmuir bool IsSystem, bool IsModuleFile,
17133c8090aSBen Langmuir bool IsMissing) {
172f0822fb0SDavid Majnemer return !isSpecialFilename(Filename) &&
173f0822fb0SDavid Majnemer (needSystemDependencies() || !IsSystem);
17433c8090aSBen Langmuir }
17533c8090aSBen Langmuir
~DependencyCollector()176637d1e66SAngel Garcia Gomez DependencyCollector::~DependencyCollector() { }
attachToPreprocessor(Preprocessor & PP)17733c8090aSBen Langmuir void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
178*0d3a2b4cSArgyrios Kyrtzidis PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(*this, PP));
1792a6edb30SRichard Smith PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
1802b3d49b6SJonas Devlieghere std::make_unique<DepCollectorMMCallbacks>(*this));
18133c8090aSBen Langmuir }
attachToASTReader(ASTReader & R)18233c8090aSBen Langmuir void DependencyCollector::attachToASTReader(ASTReader &R) {
1832b3d49b6SJonas Devlieghere R.addListener(std::make_unique<DepCollectorASTListener>(*this));
18433c8090aSBen Langmuir }
18533c8090aSBen Langmuir
DependencyFileGenerator(const DependencyOutputOptions & Opts)1868d9eb7acSAlex Lorenz DependencyFileGenerator::DependencyFileGenerator(
1878d9eb7acSAlex Lorenz const DependencyOutputOptions &Opts)
1888d9eb7acSAlex Lorenz : OutputFile(Opts.OutputFile), Targets(Opts.Targets),
18989d1fdffSDaniel Dunbar IncludeSystemHeaders(Opts.IncludeSystemHeaders),
19077b0e7f2SPeter Collingbourne PhonyTarget(Opts.UsePhonyTargets),
1918d9eb7acSAlex Lorenz AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false),
192d7214a76SPaul Robinson IncludeModuleFiles(Opts.IncludeModuleFiles),
1938d9eb7acSAlex Lorenz OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
1942e018efaSBenjamin Kramer for (const auto &ExtraDep : Opts.ExtraDeps) {
19517e5c99dSJan Svoboda if (addDependency(ExtraDep.first))
196d45d7eaeSDavid Stenberg ++InputFileIndex;
1971193f2cbSIvan Krasin }
1981193f2cbSIvan Krasin }
19916b7b6f5SEli Friedman
attachToPreprocessor(Preprocessor & PP)2008d9eb7acSAlex Lorenz void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) {
20177b0e7f2SPeter Collingbourne // Disable the "file not found" diagnostic if the -MG option was given.
2028d9eb7acSAlex Lorenz if (AddMissingHeaderDeps)
2033781a362SEli Friedman PP.SetSuppressIncludeNotFoundError(true);
20477b0e7f2SPeter Collingbourne
2058d9eb7acSAlex Lorenz DependencyCollector::attachToPreprocessor(PP);
206cb69b57bSBen Langmuir }
207cb69b57bSBen Langmuir
sawDependency(StringRef Filename,bool FromModule,bool IsSystem,bool IsModuleFile,bool IsMissing)2088d9eb7acSAlex Lorenz bool DependencyFileGenerator::sawDependency(StringRef Filename, bool FromModule,
2098d9eb7acSAlex Lorenz bool IsSystem, bool IsModuleFile,
2108d9eb7acSAlex Lorenz bool IsMissing) {
2118d9eb7acSAlex Lorenz if (IsMissing) {
2128d9eb7acSAlex Lorenz // Handle the case of missing file from an inclusion directive.
2138d9eb7acSAlex Lorenz if (AddMissingHeaderDeps)
2148d9eb7acSAlex Lorenz return true;
2158d9eb7acSAlex Lorenz SeenMissingHeader = true;
2168d9eb7acSAlex Lorenz return false;
21716b7b6f5SEli Friedman }
2188d9eb7acSAlex Lorenz if (IsModuleFile && !IncludeModuleFiles)
2198d9eb7acSAlex Lorenz return false;
22016b7b6f5SEli Friedman
221f0822fb0SDavid Majnemer if (isSpecialFilename(Filename))
22216b7b6f5SEli Friedman return false;
22316b7b6f5SEli Friedman
22416b7b6f5SEli Friedman if (IncludeSystemHeaders)
22516b7b6f5SEli Friedman return true;
22616b7b6f5SEli Friedman
2278d9eb7acSAlex Lorenz return !IsSystem;
22816b7b6f5SEli Friedman }
22916b7b6f5SEli Friedman
finishedMainFile(DiagnosticsEngine & Diags)2308d9eb7acSAlex Lorenz void DependencyFileGenerator::finishedMainFile(DiagnosticsEngine &Diags) {
2318d9eb7acSAlex Lorenz outputDependencyFile(Diags);
23216b7b6f5SEli Friedman }
23316b7b6f5SEli Friedman
23464441defSPaul Robinson /// Print the filename, with escaping or quoting that accommodates the three
23564441defSPaul Robinson /// most likely tools that use dependency files: GNU Make, BSD Make, and
23664441defSPaul Robinson /// NMake/Jom.
23764441defSPaul Robinson ///
23864441defSPaul Robinson /// BSD Make is the simplest case: It does no escaping at all. This means
23964441defSPaul Robinson /// characters that are normally delimiters, i.e. space and # (the comment
24064441defSPaul Robinson /// character) simply aren't supported in filenames.
24164441defSPaul Robinson ///
24264441defSPaul Robinson /// GNU Make does allow space and # in filenames, but to avoid being treated
24364441defSPaul Robinson /// as a delimiter or comment, these must be escaped with a backslash. Because
24464441defSPaul Robinson /// backslash is itself the escape character, if a backslash appears in a
24564441defSPaul Robinson /// filename, it should be escaped as well. (As a special case, $ is escaped
24664441defSPaul Robinson /// as $$, which is the normal Make way to handle the $ character.)
24764441defSPaul Robinson /// For compatibility with BSD Make and historical practice, if GNU Make
24864441defSPaul Robinson /// un-escapes characters in a filename but doesn't find a match, it will
24964441defSPaul Robinson /// retry with the unmodified original string.
25064441defSPaul Robinson ///
25164441defSPaul Robinson /// GCC tries to accommodate both Make formats by escaping any space or #
252fcdf3e9fSPaul Robinson /// characters in the original filename, but not escaping backslashes. The
253fcdf3e9fSPaul Robinson /// apparent intent is so that filenames with backslashes will be handled
25464441defSPaul Robinson /// correctly by BSD Make, and by GNU Make in its fallback mode of using the
25564441defSPaul Robinson /// unmodified original string; filenames with # or space characters aren't
25664441defSPaul Robinson /// supported by BSD Make at all, but will be handled correctly by GNU Make
25764441defSPaul Robinson /// due to the escaping.
25864441defSPaul Robinson ///
259fcdf3e9fSPaul Robinson /// A corner case that GCC gets only partly right is when the original filename
260fcdf3e9fSPaul Robinson /// has a backslash immediately followed by space or #. GNU Make would expect
261fcdf3e9fSPaul Robinson /// this backslash to be escaped; however GCC escapes the original backslash
262fcdf3e9fSPaul Robinson /// only when followed by space, not #. It will therefore take a dependency
263fcdf3e9fSPaul Robinson /// from a directive such as
264fcdf3e9fSPaul Robinson /// #include "a\ b\#c.h"
26564441defSPaul Robinson /// and emit it as
266fcdf3e9fSPaul Robinson /// a\\\ b\\#c.h
26764441defSPaul Robinson /// which GNU Make will interpret as
268fcdf3e9fSPaul Robinson /// a\ b\
26964441defSPaul Robinson /// followed by a comment. Failing to find this file, it will fall back to the
270fcdf3e9fSPaul Robinson /// original string, which probably doesn't exist either; in any case it won't
271fcdf3e9fSPaul Robinson /// find
272fcdf3e9fSPaul Robinson /// a\ b\#c.h
27364441defSPaul Robinson /// which is the actual filename specified by the include directive.
27464441defSPaul Robinson ///
275fcdf3e9fSPaul Robinson /// Clang does what GCC does, rather than what GNU Make expects.
27664441defSPaul Robinson ///
27764441defSPaul Robinson /// NMake/Jom has a different set of scary characters, but wraps filespecs in
27864441defSPaul Robinson /// double-quotes to avoid misinterpreting them; see
279d7214a76SPaul Robinson /// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
280d7214a76SPaul Robinson /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
281d7214a76SPaul Robinson /// for Windows file-naming info.
PrintFilename(raw_ostream & OS,StringRef Filename,DependencyOutputFormat OutputFormat)282d7214a76SPaul Robinson static void PrintFilename(raw_ostream &OS, StringRef Filename,
283d7214a76SPaul Robinson DependencyOutputFormat OutputFormat) {
284c96cb25aSDavid Bolvansky // Convert filename to platform native path
285c96cb25aSDavid Bolvansky llvm::SmallString<256> NativePath;
286c96cb25aSDavid Bolvansky llvm::sys::path::native(Filename.str(), NativePath);
287c96cb25aSDavid Bolvansky
288d7214a76SPaul Robinson if (OutputFormat == DependencyOutputFormat::NMake) {
289d7214a76SPaul Robinson // Add quotes if needed. These are the characters listed as "special" to
290d7214a76SPaul Robinson // NMake, that are legal in a Windows filespec, and that could cause
291d7214a76SPaul Robinson // misinterpretation of the dependency string.
292c96cb25aSDavid Bolvansky if (NativePath.find_first_of(" #${}^!") != StringRef::npos)
293c96cb25aSDavid Bolvansky OS << '\"' << NativePath << '\"';
294d7214a76SPaul Robinson else
295c96cb25aSDavid Bolvansky OS << NativePath;
296d7214a76SPaul Robinson return;
297d7214a76SPaul Robinson }
298fcdf3e9fSPaul Robinson assert(OutputFormat == DependencyOutputFormat::Make);
299c96cb25aSDavid Bolvansky for (unsigned i = 0, e = NativePath.size(); i != e; ++i) {
300c96cb25aSDavid Bolvansky if (NativePath[i] == '#') // Handle '#' the broken gcc way.
301fcdf3e9fSPaul Robinson OS << '\\';
302c96cb25aSDavid Bolvansky else if (NativePath[i] == ' ') { // Handle space correctly.
3035df2a4e8SChris Lattner OS << '\\';
30464441defSPaul Robinson unsigned j = i;
305c96cb25aSDavid Bolvansky while (j > 0 && NativePath[--j] == '\\')
30664441defSPaul Robinson OS << '\\';
307c96cb25aSDavid Bolvansky } else if (NativePath[i] == '$') // $ is escaped by $$.
308ae611512SBenjamin Kramer OS << '$';
309c96cb25aSDavid Bolvansky OS << NativePath[i];
3105df2a4e8SChris Lattner }
3115df2a4e8SChris Lattner }
3125df2a4e8SChris Lattner
outputDependencyFile(DiagnosticsEngine & Diags)3138d9eb7acSAlex Lorenz void DependencyFileGenerator::outputDependencyFile(DiagnosticsEngine &Diags) {
3140e7e3fc1SPeter Collingbourne if (SeenMissingHeader) {
3152a008784SRafael Espindola llvm::sys::fs::remove(OutputFile);
3160e7e3fc1SPeter Collingbourne return;
3170e7e3fc1SPeter Collingbourne }
3180e7e3fc1SPeter Collingbourne
319dae941a6SRafael Espindola std::error_code EC;
32082b3e28eSAbhina Sreeskantharajan llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
321dae941a6SRafael Espindola if (EC) {
3228d9eb7acSAlex Lorenz Diags.Report(diag::err_fe_error_opening) << OutputFile << EC.message();
3230e7e3fc1SPeter Collingbourne return;
3240e7e3fc1SPeter Collingbourne }
3250e7e3fc1SPeter Collingbourne
326459f733eSAlex Lorenz outputDependencyFile(OS);
327459f733eSAlex Lorenz }
328459f733eSAlex Lorenz
outputDependencyFile(llvm::raw_ostream & OS)329459f733eSAlex Lorenz void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
33016b7b6f5SEli Friedman // Write out the dependency targets, trying to avoid overly long
33116b7b6f5SEli Friedman // lines when possible. We try our best to emit exactly the same
33216b7b6f5SEli Friedman // dependency file as GCC (4.2), assuming the included files are the
33316b7b6f5SEli Friedman // same.
33416b7b6f5SEli Friedman const unsigned MaxColumns = 75;
33516b7b6f5SEli Friedman unsigned Columns = 0;
33616b7b6f5SEli Friedman
3373998a09dSYaron Keren for (StringRef Target : Targets) {
3383998a09dSYaron Keren unsigned N = Target.size();
33916b7b6f5SEli Friedman if (Columns == 0) {
34016b7b6f5SEli Friedman Columns += N;
34116b7b6f5SEli Friedman } else if (Columns + N + 2 > MaxColumns) {
34216b7b6f5SEli Friedman Columns = N + 2;
3430e7e3fc1SPeter Collingbourne OS << " \\\n ";
34416b7b6f5SEli Friedman } else {
34516b7b6f5SEli Friedman Columns += N + 1;
3460e7e3fc1SPeter Collingbourne OS << ' ';
34716b7b6f5SEli Friedman }
3485df2a4e8SChris Lattner // Targets already quoted as needed.
3493998a09dSYaron Keren OS << Target;
35016b7b6f5SEli Friedman }
35116b7b6f5SEli Friedman
3520e7e3fc1SPeter Collingbourne OS << ':';
35316b7b6f5SEli Friedman Columns += 1;
35416b7b6f5SEli Friedman
35516b7b6f5SEli Friedman // Now add each dependency in the order it was seen, but avoiding
35616b7b6f5SEli Friedman // duplicates.
3578d9eb7acSAlex Lorenz ArrayRef<std::string> Files = getDependencies();
3583998a09dSYaron Keren for (StringRef File : Files) {
35916b7b6f5SEli Friedman // Start a new line if this would exceed the column limit. Make
36016b7b6f5SEli Friedman // sure to leave space for a trailing " \" in case we need to
36116b7b6f5SEli Friedman // break the line on the next iteration.
3623998a09dSYaron Keren unsigned N = File.size();
36316b7b6f5SEli Friedman if (Columns + (N + 1) + 2 > MaxColumns) {
3640e7e3fc1SPeter Collingbourne OS << " \\\n ";
36516b7b6f5SEli Friedman Columns = 2;
36616b7b6f5SEli Friedman }
3670e7e3fc1SPeter Collingbourne OS << ' ';
3683998a09dSYaron Keren PrintFilename(OS, File, OutputFormat);
36916b7b6f5SEli Friedman Columns += N + 1;
37016b7b6f5SEli Friedman }
3710e7e3fc1SPeter Collingbourne OS << '\n';
37216b7b6f5SEli Friedman
37316b7b6f5SEli Friedman // Create phony targets if requested.
374193f783aSFariborz Jahanian if (PhonyTarget && !Files.empty()) {
375d45d7eaeSDavid Stenberg unsigned Index = 0;
376d45d7eaeSDavid Stenberg for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
377d45d7eaeSDavid Stenberg if (Index++ == InputFileIndex)
378d45d7eaeSDavid Stenberg continue;
3790e7e3fc1SPeter Collingbourne OS << '\n';
380fa367401SYaron Keren PrintFilename(OS, *I, OutputFormat);
3810e7e3fc1SPeter Collingbourne OS << ":\n";
38216b7b6f5SEli Friedman }
38316b7b6f5SEli Friedman }
38416b7b6f5SEli Friedman }
385