clang 17.0.0git
DependencyFile.cpp
Go to the documentation of this file.
1//===--- DependencyFile.cpp - Generate dependency file --------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This code generates dependency files.
10//
11//===----------------------------------------------------------------------===//
12
19#include "clang/Lex/ModuleMap.h"
23#include "llvm/ADT/StringSet.h"
24#include "llvm/Support/FileSystem.h"
25#include "llvm/Support/Path.h"
26#include "llvm/Support/raw_ostream.h"
27#include <optional>
28
29using namespace clang;
30
31namespace {
32struct DepCollectorPPCallbacks : public PPCallbacks {
33 DependencyCollector &DepCollector;
34 Preprocessor &PP;
35 DepCollectorPPCallbacks(DependencyCollector &L, Preprocessor &PP)
36 : DepCollector(L), PP(PP) {}
37
38 void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
39 SrcMgr::CharacteristicKind FileType, FileID PrevFID,
40 SourceLocation Loc) override {
41 if (Reason != PPCallbacks::LexedFileChangeReason::EnterFile)
42 return;
43
44 // Dependency generation really does want to go all the way to the
45 // file entry for a source location to find out what is depended on.
46 // We do not want #line markers to affect dependency generation!
47 if (std::optional<StringRef> Filename =
49 DepCollector.maybeAddDependency(
50 llvm::sys::path::remove_leading_dotslash(*Filename),
51 /*FromModule*/ false, isSystem(FileType), /*IsModuleFile*/ false,
52 &PP.getFileManager(),
53 /*IsMissing*/ false);
54 }
55
56 void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
57 SrcMgr::CharacteristicKind FileType) override {
58 StringRef Filename =
59 llvm::sys::path::remove_leading_dotslash(SkippedFile.getName());
60 DepCollector.maybeAddDependency(Filename,
61 /*FromModule=*/false,
62 /*IsSystem=*/isSystem(FileType),
63 /*IsModuleFile=*/false,
64 &PP.getFileManager(),
65 /*IsMissing=*/false);
66 }
67
68 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
69 StringRef FileName, bool IsAngled,
70 CharSourceRange FilenameRange,
71 OptionalFileEntryRef File, StringRef SearchPath,
72 StringRef RelativePath, const Module *Imported,
73 SrcMgr::CharacteristicKind FileType) override {
74 if (!File)
75 DepCollector.maybeAddDependency(FileName,
76 /*FromModule*/ false,
77 /*IsSystem*/ false,
78 /*IsModuleFile*/ false,
79 &PP.getFileManager(),
80 /*IsMissing*/ true);
81 // Files that actually exist are handled by FileChanged.
82 }
83
84 void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
86 SrcMgr::CharacteristicKind FileType) override {
87 if (!File)
88 return;
89 StringRef Filename =
90 llvm::sys::path::remove_leading_dotslash(File->getName());
91 DepCollector.maybeAddDependency(Filename,
92 /*FromModule=*/false,
93 /*IsSystem=*/isSystem(FileType),
94 /*IsModuleFile=*/false,
95 &PP.getFileManager(),
96 /*IsMissing=*/false);
97 }
98
99 void EndOfMainFile() override {
100 DepCollector.finishedMainFile(PP.getDiagnostics());
101 }
102};
103
104struct DepCollectorMMCallbacks : public ModuleMapCallbacks {
105 DependencyCollector &DepCollector;
106 DepCollectorMMCallbacks(DependencyCollector &DC) : DepCollector(DC) {}
107
108 void moduleMapFileRead(SourceLocation Loc, const FileEntry &Entry,
109 bool IsSystem) override {
110 StringRef Filename = Entry.getName();
111 DepCollector.maybeAddDependency(Filename,
112 /*FromModule*/ false,
113 /*IsSystem*/ IsSystem,
114 /*IsModuleFile*/ false,
115 /*FileMgr*/ nullptr,
116 /*IsMissing*/ false);
117 }
118};
119
120struct DepCollectorASTListener : public ASTReaderListener {
121 DependencyCollector &DepCollector;
122 FileManager &FileMgr;
123 DepCollectorASTListener(DependencyCollector &L, FileManager &FileMgr)
124 : DepCollector(L), FileMgr(FileMgr) {}
125 bool needsInputFileVisitation() override { return true; }
126 bool needsSystemInputFileVisitation() override {
127 return DepCollector.needSystemDependencies();
128 }
129 void visitModuleFile(StringRef Filename,
130 serialization::ModuleKind Kind) override {
131 DepCollector.maybeAddDependency(Filename,
132 /*FromModule*/ true,
133 /*IsSystem*/ false, /*IsModuleFile*/ true,
134 /*FileMgr*/ nullptr,
135 /*IsMissing*/ false);
136 }
137 bool visitInputFile(StringRef Filename, bool IsSystem,
138 bool IsOverridden, bool IsExplicitModule) override {
139 if (IsOverridden || IsExplicitModule)
140 return true;
141
142 // Run this through the FileManager in order to respect 'use-external-name'
143 // in case we have a VFS overlay.
144 if (auto FE = FileMgr.getOptionalFileRef(Filename))
145 Filename = FE->getName();
146
147 DepCollector.maybeAddDependency(Filename, /*FromModule*/ true, IsSystem,
148 /*IsModuleFile*/ false, /*FileMgr*/ nullptr,
149 /*IsMissing*/ false);
150 return true;
151 }
152};
153} // end anonymous namespace
154
156 bool FromModule, bool IsSystem,
157 bool IsModuleFile,
158 FileManager *FileMgr,
159 bool IsMissing) {
160 if (sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing)) {
161 if (IsSystem && FileMgr && shouldCanonicalizeSystemDependencies()) {
162 if (auto F = FileMgr->getFile(Filename))
163 Filename = FileMgr->getCanonicalName(*F);
164 }
166 }
167}
168
170 StringRef SearchPath;
171#ifdef _WIN32
172 // Make the search insensitive to case and separators.
174 llvm::sys::path::native(TmpPath);
175 std::transform(TmpPath.begin(), TmpPath.end(), TmpPath.begin(), ::tolower);
176 SearchPath = TmpPath.str();
177#else
178 SearchPath = Filename;
179#endif
180
181 if (Seen.insert(SearchPath).second) {
182 Dependencies.push_back(std::string(Filename));
183 return true;
184 }
185 return false;
186}
187
188static bool isSpecialFilename(StringRef Filename) {
189 return Filename == "<built-in>";
190}
191
192bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
193 bool IsSystem, bool IsModuleFile,
194 bool IsMissing) {
195 return !isSpecialFilename(Filename) &&
196 (needSystemDependencies() || !IsSystem);
197}
198
201 PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(*this, PP));
203 std::make_unique<DepCollectorMMCallbacks>(*this));
204}
206 R.addListener(
207 std::make_unique<DepCollectorASTListener>(*this, R.getFileManager()));
208}
209
211 const DependencyOutputOptions &Opts)
212 : OutputFile(Opts.OutputFile), Targets(Opts.Targets),
213 IncludeSystemHeaders(Opts.IncludeSystemHeaders),
214 CanonicalSystemHeaders(Opts.CanonicalSystemHeaders),
215 PhonyTarget(Opts.UsePhonyTargets),
216 AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false),
217 IncludeModuleFiles(Opts.IncludeModuleFiles),
218 OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
219 for (const auto &ExtraDep : Opts.ExtraDeps) {
220 if (addDependency(ExtraDep.first))
221 ++InputFileIndex;
222 }
223}
224
226 // Disable the "file not found" diagnostic if the -MG option was given.
227 if (AddMissingHeaderDeps)
229
231}
232
233bool DependencyFileGenerator::sawDependency(StringRef Filename, bool FromModule,
234 bool IsSystem, bool IsModuleFile,
235 bool IsMissing) {
236 if (IsMissing) {
237 // Handle the case of missing file from an inclusion directive.
238 if (AddMissingHeaderDeps)
239 return true;
240 SeenMissingHeader = true;
241 return false;
242 }
243 if (IsModuleFile && !IncludeModuleFiles)
244 return false;
245
247 return false;
248
249 if (IncludeSystemHeaders)
250 return true;
251
252 return !IsSystem;
253}
254
257}
258
259/// Print the filename, with escaping or quoting that accommodates the three
260/// most likely tools that use dependency files: GNU Make, BSD Make, and
261/// NMake/Jom.
262///
263/// BSD Make is the simplest case: It does no escaping at all. This means
264/// characters that are normally delimiters, i.e. space and # (the comment
265/// character) simply aren't supported in filenames.
266///
267/// GNU Make does allow space and # in filenames, but to avoid being treated
268/// as a delimiter or comment, these must be escaped with a backslash. Because
269/// backslash is itself the escape character, if a backslash appears in a
270/// filename, it should be escaped as well. (As a special case, $ is escaped
271/// as $$, which is the normal Make way to handle the $ character.)
272/// For compatibility with BSD Make and historical practice, if GNU Make
273/// un-escapes characters in a filename but doesn't find a match, it will
274/// retry with the unmodified original string.
275///
276/// GCC tries to accommodate both Make formats by escaping any space or #
277/// characters in the original filename, but not escaping backslashes. The
278/// apparent intent is so that filenames with backslashes will be handled
279/// correctly by BSD Make, and by GNU Make in its fallback mode of using the
280/// unmodified original string; filenames with # or space characters aren't
281/// supported by BSD Make at all, but will be handled correctly by GNU Make
282/// due to the escaping.
283///
284/// A corner case that GCC gets only partly right is when the original filename
285/// has a backslash immediately followed by space or #. GNU Make would expect
286/// this backslash to be escaped; however GCC escapes the original backslash
287/// only when followed by space, not #. It will therefore take a dependency
288/// from a directive such as
289/// #include "a\ b\#c.h"
290/// and emit it as
291/// a\\\ b\\#c.h
292/// which GNU Make will interpret as
293/// a\ b\
294/// followed by a comment. Failing to find this file, it will fall back to the
295/// original string, which probably doesn't exist either; in any case it won't
296/// find
297/// a\ b\#c.h
298/// which is the actual filename specified by the include directive.
299///
300/// Clang does what GCC does, rather than what GNU Make expects.
301///
302/// NMake/Jom has a different set of scary characters, but wraps filespecs in
303/// double-quotes to avoid misinterpreting them; see
304/// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
305/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
306/// for Windows file-naming info.
307static void PrintFilename(raw_ostream &OS, StringRef Filename,
308 DependencyOutputFormat OutputFormat) {
309 // Convert filename to platform native path
310 llvm::SmallString<256> NativePath;
311 llvm::sys::path::native(Filename.str(), NativePath);
312
313 if (OutputFormat == DependencyOutputFormat::NMake) {
314 // Add quotes if needed. These are the characters listed as "special" to
315 // NMake, that are legal in a Windows filespec, and that could cause
316 // misinterpretation of the dependency string.
317 if (NativePath.find_first_of(" #${}^!") != StringRef::npos)
318 OS << '\"' << NativePath << '\"';
319 else
320 OS << NativePath;
321 return;
322 }
323 assert(OutputFormat == DependencyOutputFormat::Make);
324 for (unsigned i = 0, e = NativePath.size(); i != e; ++i) {
325 if (NativePath[i] == '#') // Handle '#' the broken gcc way.
326 OS << '\\';
327 else if (NativePath[i] == ' ') { // Handle space correctly.
328 OS << '\\';
329 unsigned j = i;
330 while (j > 0 && NativePath[--j] == '\\')
331 OS << '\\';
332 } else if (NativePath[i] == '$') // $ is escaped by $$.
333 OS << '$';
334 OS << NativePath[i];
335 }
336}
337
339 if (SeenMissingHeader) {
340 llvm::sys::fs::remove(OutputFile);
341 return;
342 }
343
344 std::error_code EC;
345 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
346 if (EC) {
347 Diags.Report(diag::err_fe_error_opening) << OutputFile << EC.message();
348 return;
349 }
350
352}
353
355 // Write out the dependency targets, trying to avoid overly long
356 // lines when possible. We try our best to emit exactly the same
357 // dependency file as GCC>=10, assuming the included files are the
358 // same.
359 const unsigned MaxColumns = 75;
360 unsigned Columns = 0;
361
362 for (StringRef Target : Targets) {
363 unsigned N = Target.size();
364 if (Columns == 0) {
365 Columns += N;
366 } else if (Columns + N + 2 > MaxColumns) {
367 Columns = N + 2;
368 OS << " \\\n ";
369 } else {
370 Columns += N + 1;
371 OS << ' ';
372 }
373 // Targets already quoted as needed.
374 OS << Target;
375 }
376
377 OS << ':';
378 Columns += 1;
379
380 // Now add each dependency in the order it was seen, but avoiding
381 // duplicates.
383 for (StringRef File : Files) {
384 if (File == "<stdin>")
385 continue;
386 // Start a new line if this would exceed the column limit. Make
387 // sure to leave space for a trailing " \" in case we need to
388 // break the line on the next iteration.
389 unsigned N = File.size();
390 if (Columns + (N + 1) + 2 > MaxColumns) {
391 OS << " \\\n ";
392 Columns = 2;
393 }
394 OS << ' ';
395 PrintFilename(OS, File, OutputFormat);
396 Columns += N + 1;
397 }
398 OS << '\n';
399
400 // Create phony targets if requested.
401 if (PhonyTarget && !Files.empty()) {
402 unsigned Index = 0;
403 for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
404 if (Index++ == InputFileIndex)
405 continue;
406 PrintFilename(OS, *I, OutputFormat);
407 OS << ":\n";
408 }
409 }
410}
static void PrintFilename(raw_ostream &OS, StringRef Filename, DependencyOutputFormat OutputFormat)
Print the filename, with escaping or quoting that accommodates the three most likely tools that use d...
static bool isSpecialFilename(StringRef Filename)
Defines the clang::FileManager interface and associated types.
StringRef Filename
Definition: Format.cpp:2795
Defines the PPCallbacks interface.
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:113
virtual bool needsInputFileVisitation()
Returns true if this ASTReaderListener wants to receive the input files of the AST file via visitInpu...
Definition: ASTReader.h:217
virtual bool visitInputFile(StringRef Filename, bool isSystem, bool isOverridden, bool isExplicitModule)
if needsInputFileVisitation returns true, this is called for each non-system input file of the AST Fi...
Definition: ASTReader.h:229
virtual void visitModuleFile(StringRef Filename, serialization::ModuleKind Kind)
This is called for each AST file loaded.
Definition: ASTReader.h:212
virtual bool needsSystemInputFileVisitation()
Returns true if this ASTReaderListener wants to receive the system input files of the AST file via vi...
Definition: ASTReader.h:221
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:366
void addListener(std::unique_ptr< ASTReaderListener > L)
Add an AST callback listener.
Definition: ASTReader.h:1676
FileManager & getFileManager() const
Definition: ASTReader.h:1588
Represents a character-granular source range.
An interface for collecting the dependencies of a compilation.
Definition: Utils.h:62
bool addDependency(StringRef Filename)
Return true if the filename was added to the list of dependencies, false otherwise.
virtual void attachToPreprocessor(Preprocessor &PP)
ArrayRef< std::string > getDependencies() const
Definition: Utils.h:68
virtual void finishedMainFile(DiagnosticsEngine &Diags)
Called when the end of the main file is reached.
Definition: Utils.h:78
virtual void attachToASTReader(ASTReader &R)
virtual void maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, FileManager *FileMgr, bool IsMissing)
Add a dependency Filename if it has not been seen before and sawDependency() returns true.
virtual bool shouldCanonicalizeSystemDependencies()
Return true if system files should be canonicalized.
Definition: Utils.h:84
virtual bool needSystemDependencies()
Return true if system files should be passed to sawDependency().
Definition: Utils.h:81
virtual bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsMissing)
Called when a new file is seen.
void outputDependencyFile(llvm::raw_ostream &OS)
void attachToPreprocessor(Preprocessor &PP) override
void finishedMainFile(DiagnosticsEngine &Diags) override
Called when the end of the main file is reached.
bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsMissing) final
Called when a new file is seen.
DependencyFileGenerator(const DependencyOutputOptions &Opts)
DependencyOutputOptions - Options for controlling the compiler dependency file generation.
std::vector< std::pair< std::string, ExtraDepKind > > ExtraDeps
A list of extra dependencies (filename and kind) to be used for every target.
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:192
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1542
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition: FileEntry.h:57
StringRef getName() const
The name of this FileEntry.
Definition: FileEntry.h:61
Cached information about one file (either on disk or in the virtual file system).
Definition: FileEntry.h:353
StringRef getName() const
Definition: FileEntry.h:384
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Implements support for file system lookup, file system caching, and directory search management.
Definition: FileManager.h:53
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
Definition: FileManager.h:234
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
StringRef getCanonicalName(const DirectoryEntry *Dir)
Retrieve the canonical name for a given directory.
ModuleMap & getModuleMap()
Retrieve the module map.
Definition: HeaderSearch.h:795
Record the location of an inclusion directive, such as an #include or #import statement.
A mechanism to observe the actions of the module map parser as it reads module map files.
Definition: ModuleMap.h:48
virtual void moduleMapFileRead(SourceLocation FileStart, const FileEntry &File, bool IsSystem)
Called when a module map file has been read.
Definition: ModuleMap.h:60
void addModuleMapCallbacks(std::unique_ptr< ModuleMapCallbacks > Callback)
Add a module map callback.
Definition: ModuleMap.h:424
Describes a module or submodule.
Definition: Module.h:98
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition: PPCallbacks.h:35
virtual void EndOfMainFile()
Callback invoked when the end of the main file is reached.
Definition: PPCallbacks.h:185
virtual void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok, SrcMgr::CharacteristicKind FileType)
Callback invoked whenever a source file is skipped as the result of header guard optimization.
Definition: PPCallbacks.h:82
virtual void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled, OptionalFileEntryRef File, SrcMgr::CharacteristicKind FileType)
Hook called when a '__has_include' or '__has_include_next' directive is read.
Definition: PPCallbacks.cpp:17
virtual void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID, SourceLocation Loc)
Callback invoked whenever the Lexer moves to a different file for lexing.
Definition: PPCallbacks.h:70
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
SourceManager & getSourceManager() const
FileManager & getFileManager() const
HeaderSearch & getHeaderSearchInfo() const
void SetSuppressIncludeNotFoundError(bool Suppress)
DiagnosticsEngine & getDiagnostics() const
Encodes a location in the source.
std::optional< StringRef > getNonBuiltinFilenameForID(FileID FID) const
Returns the filename for the provided FileID, unless it's a built-in buffer that's not represented by...
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
Definition: SourceManager.h:80
bool isSystem(CharacteristicKind CK)
Determine whether a file / directory characteristic is for system code.
Definition: SourceManager.h:89
ModuleKind
Specifies the kind of module that has been loaded.
Definition: ModuleFile.h:42
DependencyOutputFormat
DependencyOutputFormat - Format for the compiler dependency file.
#define false
Definition: stdbool.h:22