clang 20.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,
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 /*IsMissing*/ false);
53 }
54
55 void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
57 StringRef Filename =
58 llvm::sys::path::remove_leading_dotslash(SkippedFile.getName());
59 DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
60 /*IsSystem=*/isSystem(FileType),
61 /*IsModuleFile=*/false,
62 /*IsMissing=*/false);
63 }
64
65 void EmbedDirective(SourceLocation, StringRef, bool,
67 const LexEmbedParametersResult &) override {
68 assert(File && "expected to only be called when the file is found");
69 StringRef FileName =
70 llvm::sys::path::remove_leading_dotslash(File->getName());
71 DepCollector.maybeAddDependency(FileName,
72 /*FromModule*/ false,
73 /*IsSystem*/ false,
74 /*IsModuleFile*/ false,
75 /*IsMissing*/ false);
76 }
77
78 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
79 StringRef FileName, bool IsAngled,
80 CharSourceRange FilenameRange,
81 OptionalFileEntryRef File, StringRef SearchPath,
82 StringRef RelativePath, const Module *SuggestedModule,
83 bool ModuleImported,
85 if (!File)
86 DepCollector.maybeAddDependency(FileName, /*FromModule*/ false,
87 /*IsSystem*/ false,
88 /*IsModuleFile*/ false,
89 /*IsMissing*/ true);
90 // Files that actually exist are handled by FileChanged.
91 }
92
93 void HasEmbed(SourceLocation, StringRef, bool,
94 OptionalFileEntryRef File) override {
95 if (!File)
96 return;
97 StringRef Filename =
98 llvm::sys::path::remove_leading_dotslash(File->getName());
99 DepCollector.maybeAddDependency(Filename,
100 /*FromModule=*/false, false,
101 /*IsModuleFile=*/false,
102 /*IsMissing=*/false);
103 }
104
105 void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
108 if (!File)
109 return;
110 StringRef Filename =
111 llvm::sys::path::remove_leading_dotslash(File->getName());
112 DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
113 /*IsSystem=*/isSystem(FileType),
114 /*IsModuleFile=*/false,
115 /*IsMissing=*/false);
116 }
117
118 void EndOfMainFile() override {
119 DepCollector.finishedMainFile(PP.getDiagnostics());
120 }
121};
122
123struct DepCollectorMMCallbacks : public ModuleMapCallbacks {
124 DependencyCollector &DepCollector;
125 DepCollectorMMCallbacks(DependencyCollector &DC) : DepCollector(DC) {}
126
128 bool IsSystem) override {
129 StringRef Filename = Entry.getName();
130 DepCollector.maybeAddDependency(Filename, /*FromModule*/ false,
131 /*IsSystem*/ IsSystem,
132 /*IsModuleFile*/ false,
133 /*IsMissing*/ false);
134 }
135};
136
137struct DepCollectorASTListener : public ASTReaderListener {
138 DependencyCollector &DepCollector;
139 FileManager &FileMgr;
140 DepCollectorASTListener(DependencyCollector &L, FileManager &FileMgr)
141 : DepCollector(L), FileMgr(FileMgr) {}
142 bool needsInputFileVisitation() override { return true; }
143 bool needsSystemInputFileVisitation() override {
144 return DepCollector.needSystemDependencies();
145 }
146 void visitModuleFile(StringRef Filename,
147 serialization::ModuleKind Kind) override {
148 DepCollector.maybeAddDependency(Filename, /*FromModule*/ true,
149 /*IsSystem*/ false, /*IsModuleFile*/ true,
150 /*IsMissing*/ false);
151 }
152 bool visitInputFile(StringRef Filename, bool IsSystem,
153 bool IsOverridden, bool IsExplicitModule) override {
154 if (IsOverridden || IsExplicitModule)
155 return true;
156
157 // Run this through the FileManager in order to respect 'use-external-name'
158 // in case we have a VFS overlay.
159 if (auto FE = FileMgr.getOptionalFileRef(Filename))
160 Filename = FE->getName();
161
162 DepCollector.maybeAddDependency(Filename, /*FromModule*/ true, IsSystem,
163 /*IsModuleFile*/ false,
164 /*IsMissing*/ false);
165 return true;
166 }
167};
168} // end anonymous namespace
169
171 bool FromModule, bool IsSystem,
172 bool IsModuleFile,
173 bool IsMissing) {
174 if (sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
176}
177
179 StringRef SearchPath;
180#ifdef _WIN32
181 // Make the search insensitive to case and separators.
183 llvm::sys::path::native(TmpPath);
184 std::transform(TmpPath.begin(), TmpPath.end(), TmpPath.begin(), ::tolower);
185 SearchPath = TmpPath.str();
186#else
187 SearchPath = Filename;
188#endif
189
190 if (Seen.insert(SearchPath).second) {
191 Dependencies.push_back(std::string(Filename));
192 return true;
193 }
194 return false;
195}
196
197static bool isSpecialFilename(StringRef Filename) {
198 return Filename == "<built-in>";
199}
200
201bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
202 bool IsSystem, bool IsModuleFile,
203 bool IsMissing) {
204 return !isSpecialFilename(Filename) &&
205 (needSystemDependencies() || !IsSystem);
206}
207
210 PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(*this, PP));
212 std::make_unique<DepCollectorMMCallbacks>(*this));
213}
215 R.addListener(
216 std::make_unique<DepCollectorASTListener>(*this, R.getFileManager()));
217}
218
220 const DependencyOutputOptions &Opts)
221 : OutputFile(Opts.OutputFile), Targets(Opts.Targets),
222 IncludeSystemHeaders(Opts.IncludeSystemHeaders),
223 PhonyTarget(Opts.UsePhonyTargets),
224 AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false),
225 IncludeModuleFiles(Opts.IncludeModuleFiles),
226 OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
227 for (const auto &ExtraDep : Opts.ExtraDeps) {
228 if (addDependency(ExtraDep.first))
229 ++InputFileIndex;
230 }
231}
232
234 // Disable the "file not found" diagnostic if the -MG option was given.
235 if (AddMissingHeaderDeps)
237
239}
240
241bool DependencyFileGenerator::sawDependency(StringRef Filename, bool FromModule,
242 bool IsSystem, bool IsModuleFile,
243 bool IsMissing) {
244 if (IsMissing) {
245 // Handle the case of missing file from an inclusion directive.
246 if (AddMissingHeaderDeps)
247 return true;
248 SeenMissingHeader = true;
249 return false;
250 }
251 if (IsModuleFile && !IncludeModuleFiles)
252 return false;
253
255 return false;
256
257 if (IncludeSystemHeaders)
258 return true;
259
260 return !IsSystem;
261}
262
265}
266
267/// Print the filename, with escaping or quoting that accommodates the three
268/// most likely tools that use dependency files: GNU Make, BSD Make, and
269/// NMake/Jom.
270///
271/// BSD Make is the simplest case: It does no escaping at all. This means
272/// characters that are normally delimiters, i.e. space and # (the comment
273/// character) simply aren't supported in filenames.
274///
275/// GNU Make does allow space and # in filenames, but to avoid being treated
276/// as a delimiter or comment, these must be escaped with a backslash. Because
277/// backslash is itself the escape character, if a backslash appears in a
278/// filename, it should be escaped as well. (As a special case, $ is escaped
279/// as $$, which is the normal Make way to handle the $ character.)
280/// For compatibility with BSD Make and historical practice, if GNU Make
281/// un-escapes characters in a filename but doesn't find a match, it will
282/// retry with the unmodified original string.
283///
284/// GCC tries to accommodate both Make formats by escaping any space or #
285/// characters in the original filename, but not escaping backslashes. The
286/// apparent intent is so that filenames with backslashes will be handled
287/// correctly by BSD Make, and by GNU Make in its fallback mode of using the
288/// unmodified original string; filenames with # or space characters aren't
289/// supported by BSD Make at all, but will be handled correctly by GNU Make
290/// due to the escaping.
291///
292/// A corner case that GCC gets only partly right is when the original filename
293/// has a backslash immediately followed by space or #. GNU Make would expect
294/// this backslash to be escaped; however GCC escapes the original backslash
295/// only when followed by space, not #. It will therefore take a dependency
296/// from a directive such as
297/// #include "a\ b\#c.h"
298/// and emit it as
299/// a\\\ b\\#c.h
300/// which GNU Make will interpret as
301/// a\ b\
302/// followed by a comment. Failing to find this file, it will fall back to the
303/// original string, which probably doesn't exist either; in any case it won't
304/// find
305/// a\ b\#c.h
306/// which is the actual filename specified by the include directive.
307///
308/// Clang does what GCC does, rather than what GNU Make expects.
309///
310/// NMake/Jom has a different set of scary characters, but wraps filespecs in
311/// double-quotes to avoid misinterpreting them; see
312/// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
313/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
314/// for Windows file-naming info.
315static void PrintFilename(raw_ostream &OS, StringRef Filename,
316 DependencyOutputFormat OutputFormat) {
317 // Convert filename to platform native path
318 llvm::SmallString<256> NativePath;
319 llvm::sys::path::native(Filename.str(), NativePath);
320
321 if (OutputFormat == DependencyOutputFormat::NMake) {
322 // Add quotes if needed. These are the characters listed as "special" to
323 // NMake, that are legal in a Windows filespec, and that could cause
324 // misinterpretation of the dependency string.
325 if (NativePath.find_first_of(" #${}^!") != StringRef::npos)
326 OS << '\"' << NativePath << '\"';
327 else
328 OS << NativePath;
329 return;
330 }
331 assert(OutputFormat == DependencyOutputFormat::Make);
332 for (unsigned i = 0, e = NativePath.size(); i != e; ++i) {
333 if (NativePath[i] == '#') // Handle '#' the broken gcc way.
334 OS << '\\';
335 else if (NativePath[i] == ' ') { // Handle space correctly.
336 OS << '\\';
337 unsigned j = i;
338 while (j > 0 && NativePath[--j] == '\\')
339 OS << '\\';
340 } else if (NativePath[i] == '$') // $ is escaped by $$.
341 OS << '$';
342 OS << NativePath[i];
343 }
344}
345
347 if (SeenMissingHeader) {
348 llvm::sys::fs::remove(OutputFile);
349 return;
350 }
351
352 std::error_code EC;
353 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
354 if (EC) {
355 Diags.Report(diag::err_fe_error_opening) << OutputFile << EC.message();
356 return;
357 }
358
360}
361
363 // Write out the dependency targets, trying to avoid overly long
364 // lines when possible. We try our best to emit exactly the same
365 // dependency file as GCC>=10, assuming the included files are the
366 // same.
367 const unsigned MaxColumns = 75;
368 unsigned Columns = 0;
369
370 for (StringRef Target : Targets) {
371 unsigned N = Target.size();
372 if (Columns == 0) {
373 Columns += N;
374 } else if (Columns + N + 2 > MaxColumns) {
375 Columns = N + 2;
376 OS << " \\\n ";
377 } else {
378 Columns += N + 1;
379 OS << ' ';
380 }
381 // Targets already quoted as needed.
382 OS << Target;
383 }
384
385 OS << ':';
386 Columns += 1;
387
388 // Now add each dependency in the order it was seen, but avoiding
389 // duplicates.
391 for (StringRef File : Files) {
392 if (File == "<stdin>")
393 continue;
394 // Start a new line if this would exceed the column limit. Make
395 // sure to leave space for a trailing " \" in case we need to
396 // break the line on the next iteration.
397 unsigned N = File.size();
398 if (Columns + (N + 1) + 2 > MaxColumns) {
399 OS << " \\\n ";
400 Columns = 2;
401 }
402 OS << ' ';
403 PrintFilename(OS, File, OutputFormat);
404 Columns += N + 1;
405 }
406 OS << '\n';
407
408 // Create phony targets if requested.
409 if (PhonyTarget && !Files.empty()) {
410 unsigned Index = 0;
411 for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
412 if (Index++ == InputFileIndex)
413 continue;
414 PrintFilename(OS, *I, OutputFormat);
415 OS << ":\n";
416 }
417 }
418}
Expr * E
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:3001
llvm::MachO::FileType FileType
Definition: MachO.h:46
llvm::MachO::Target Target
Definition: MachO.h:51
Defines the PPCallbacks interface.
Defines the clang::Preprocessor interface.
SourceLocation Loc
Definition: SemaObjC.cpp:759
Defines the SourceManager interface.
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:114
virtual bool needsInputFileVisitation()
Returns true if this ASTReaderListener wants to receive the input files of the AST file via visitInpu...
Definition: ASTReader.h:221
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:233
virtual void visitModuleFile(StringRef Filename, serialization::ModuleKind Kind)
This is called for each AST file loaded.
Definition: ASTReader.h:216
virtual bool needsSystemInputFileVisitation()
Returns true if this ASTReaderListener wants to receive the system input files of the AST file via vi...
Definition: ASTReader.h:225
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:378
void addListener(std::unique_ptr< ASTReaderListener > L)
Add an AST callback listener.
Definition: ASTReader.h:1716
FileManager & getFileManager() const
Definition: ASTReader.h:1623
Represents a character-granular source range.
An interface for collecting the dependencies of a compilation.
Definition: Utils.h:63
virtual void maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsMissing)
Add a dependency Filename if it has not been seen before and sawDependency() returns true.
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:69
virtual void finishedMainFile(DiagnosticsEngine &Diags)
Called when the end of the main file is reached.
Definition: Utils.h:79
virtual void attachToASTReader(ASTReader &R)
virtual bool needSystemDependencies()
Return true if system files should be passed to sawDependency().
Definition: Utils.h:82
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:1547
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
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:240
ModuleMap & getModuleMap()
Retrieve the module map.
Definition: HeaderSearch.h:833
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, FileEntryRef 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:105
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition: PPCallbacks.h:36
virtual void HasEmbed(SourceLocation Loc, StringRef FileName, bool IsAngled, OptionalFileEntryRef File)
Hook called when a '__has_embed' directive is read.
Definition: PPCallbacks.h:366
virtual void EndOfMainFile()
Callback invoked when the end of the main file is reached.
Definition: PPCallbacks.h:217
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:83
virtual void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool IsAngled, OptionalFileEntryRef File, const LexEmbedParametersResult &Params)
Callback invoked whenever an embed directive has been processed, regardless of whether the embed will...
Definition: PPCallbacks.h:111
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:71
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:137
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
SourceManager & getSourceManager() 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:36
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
Definition: SourceManager.h:81
bool isSystem(CharacteristicKind CK)
Determine whether a file / directory characteristic is for system code.
Definition: SourceManager.h:90
ModuleKind
Specifies the kind of module that has been loaded.
Definition: ModuleFile.h:42
The JSON file list parser is used to communicate input to InstallAPI.
DependencyOutputFormat
DependencyOutputFormat - Format for the compiler dependency file.
#define false
Definition: stdbool.h:26