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