clang  8.0.0svn
DependencyFile.cpp
Go to the documentation of this file.
1 //===--- DependencyFile.cpp - Generate dependency file --------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This code generates dependency files.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/Frontend/Utils.h"
21 #include "clang/Lex/ModuleMap.h"
22 #include "clang/Lex/PPCallbacks.h"
23 #include "clang/Lex/Preprocessor.h"
25 #include "llvm/ADT/StringSet.h"
26 #include "llvm/ADT/StringSwitch.h"
27 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/Path.h"
29 #include "llvm/Support/raw_ostream.h"
30 
31 using namespace clang;
32 
33 namespace {
34 struct DepCollectorPPCallbacks : public PPCallbacks {
35  DependencyCollector &DepCollector;
37  DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM)
38  : DepCollector(L), SM(SM) { }
39 
40  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
42  FileID PrevFID) override {
43  if (Reason != PPCallbacks::EnterFile)
44  return;
45 
46  // Dependency generation really does want to go all the way to the
47  // file entry for a source location to find out what is depended on.
48  // We do not want #line markers to affect dependency generation!
49  const FileEntry *FE =
51  if (!FE)
52  return;
53 
54  StringRef Filename =
55  llvm::sys::path::remove_leading_dotslash(FE->getName());
56 
57  DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
58  isSystem(FileType),
59  /*IsModuleFile*/false, /*IsMissing*/false);
60  }
61 
62  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
63  StringRef FileName, bool IsAngled,
64  CharSourceRange FilenameRange, const FileEntry *File,
65  StringRef SearchPath, StringRef RelativePath,
66  const Module *Imported,
67  SrcMgr::CharacteristicKind FileType) override {
68  if (!File)
69  DepCollector.maybeAddDependency(FileName, /*FromModule*/false,
70  /*IsSystem*/false, /*IsModuleFile*/false,
71  /*IsMissing*/true);
72  // Files that actually exist are handled by FileChanged.
73  }
74 
75  void EndOfMainFile() override {
76  DepCollector.finishedMainFile();
77  }
78 };
79 
80 struct DepCollectorMMCallbacks : public ModuleMapCallbacks {
81  DependencyCollector &DepCollector;
82  DepCollectorMMCallbacks(DependencyCollector &DC) : DepCollector(DC) {}
83 
84  void moduleMapFileRead(SourceLocation Loc, const FileEntry &Entry,
85  bool IsSystem) override {
86  StringRef Filename = Entry.getName();
87  DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
88  /*IsSystem*/IsSystem,
89  /*IsModuleFile*/false,
90  /*IsMissing*/false);
91  }
92 };
93 
94 struct DepCollectorASTListener : public ASTReaderListener {
95  DependencyCollector &DepCollector;
96  DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
97  bool needsInputFileVisitation() override { return true; }
98  bool needsSystemInputFileVisitation() override {
99  return DepCollector.needSystemDependencies();
100  }
101  void visitModuleFile(StringRef Filename,
102  serialization::ModuleKind Kind) override {
103  DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
104  /*IsSystem*/false, /*IsModuleFile*/true,
105  /*IsMissing*/false);
106  }
107  bool visitInputFile(StringRef Filename, bool IsSystem,
108  bool IsOverridden, bool IsExplicitModule) override {
109  if (IsOverridden || IsExplicitModule)
110  return true;
111 
112  DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem,
113  /*IsModuleFile*/false, /*IsMissing*/false);
114  return true;
115  }
116 };
117 } // end anonymous namespace
118 
119 void DependencyCollector::maybeAddDependency(StringRef Filename, bool FromModule,
120  bool IsSystem, bool IsModuleFile,
121  bool IsMissing) {
122  if (Seen.insert(Filename).second &&
123  sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
124  Dependencies.push_back(Filename);
125 }
126 
127 static bool isSpecialFilename(StringRef Filename) {
128  return llvm::StringSwitch<bool>(Filename)
129  .Case("<built-in>", true)
130  .Case("<stdin>", true)
131  .Default(false);
132 }
133 
134 bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
135  bool IsSystem, bool IsModuleFile,
136  bool IsMissing) {
137  return !isSpecialFilename(Filename) &&
138  (needSystemDependencies() || !IsSystem);
139 }
140 
143  PP.addPPCallbacks(
144  llvm::make_unique<DepCollectorPPCallbacks>(*this, PP.getSourceManager()));
146  llvm::make_unique<DepCollectorMMCallbacks>(*this));
147 }
149  R.addListener(llvm::make_unique<DepCollectorASTListener>(*this));
150 }
151 
152 namespace {
153 /// Private implementation for DependencyFileGenerator
154 class DFGImpl : public PPCallbacks {
155  std::vector<std::string> Files;
156  llvm::StringSet<> FilesSet;
157  const Preprocessor *PP;
158  std::string OutputFile;
159  std::vector<std::string> Targets;
160  bool IncludeSystemHeaders;
161  bool PhonyTarget;
162  bool AddMissingHeaderDeps;
163  bool SeenMissingHeader;
164  bool IncludeModuleFiles;
165  DependencyOutputFormat OutputFormat;
166  unsigned InputFileIndex;
167 
168 private:
169  bool FileMatchesDepCriteria(const char *Filename,
170  SrcMgr::CharacteristicKind FileType);
171  void OutputDependencyFile();
172 
173 public:
174  DFGImpl(const Preprocessor *_PP, const DependencyOutputOptions &Opts)
175  : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets),
176  IncludeSystemHeaders(Opts.IncludeSystemHeaders),
177  PhonyTarget(Opts.UsePhonyTargets),
178  AddMissingHeaderDeps(Opts.AddMissingHeaderDeps),
179  SeenMissingHeader(false),
180  IncludeModuleFiles(Opts.IncludeModuleFiles),
181  OutputFormat(Opts.OutputFormat),
182  InputFileIndex(0) {
183  for (const auto &ExtraDep : Opts.ExtraDeps) {
184  if (AddFilename(ExtraDep))
185  ++InputFileIndex;
186  }
187  }
188 
189  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
191  FileID PrevFID) override;
192 
193  void FileSkipped(const FileEntry &SkippedFile, const Token &FilenameTok,
194  SrcMgr::CharacteristicKind FileType) override;
195 
196  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
197  StringRef FileName, bool IsAngled,
198  CharSourceRange FilenameRange, const FileEntry *File,
199  StringRef SearchPath, StringRef RelativePath,
200  const Module *Imported,
201  SrcMgr::CharacteristicKind FileType) override;
202 
203  void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
204  const FileEntry *File,
205  SrcMgr::CharacteristicKind FileType) override;
206 
207  void EndOfMainFile() override {
208  OutputDependencyFile();
209  }
210 
211  bool AddFilename(StringRef Filename);
212  bool includeSystemHeaders() const { return IncludeSystemHeaders; }
213  bool includeModuleFiles() const { return IncludeModuleFiles; }
214 };
215 
216 class DFGMMCallback : public ModuleMapCallbacks {
217  DFGImpl &Parent;
218 public:
219  DFGMMCallback(DFGImpl &Parent) : Parent(Parent) {}
220  void moduleMapFileRead(SourceLocation Loc, const FileEntry &Entry,
221  bool IsSystem) override {
222  if (!IsSystem || Parent.includeSystemHeaders())
223  Parent.AddFilename(Entry.getName());
224  }
225 };
226 
227 class DFGASTReaderListener : public ASTReaderListener {
228  DFGImpl &Parent;
229 public:
230  DFGASTReaderListener(DFGImpl &Parent)
231  : Parent(Parent) { }
232  bool needsInputFileVisitation() override { return true; }
233  bool needsSystemInputFileVisitation() override {
234  return Parent.includeSystemHeaders();
235  }
236  void visitModuleFile(StringRef Filename,
237  serialization::ModuleKind Kind) override;
238  bool visitInputFile(StringRef Filename, bool isSystem,
239  bool isOverridden, bool isExplicitModule) override;
240 };
241 }
242 
243 DependencyFileGenerator::DependencyFileGenerator(void *Impl)
244 : Impl(Impl) { }
245 
248 
249  if (Opts.Targets.empty()) {
250  PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
251  return nullptr;
252  }
253 
254  // Disable the "file not found" diagnostic if the -MG option was given.
255  if (Opts.AddMissingHeaderDeps)
257 
258  DFGImpl *Callback = new DFGImpl(&PP, Opts);
259  PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callback));
261  llvm::make_unique<DFGMMCallback>(*Callback));
262  return new DependencyFileGenerator(Callback);
263 }
264 
266  DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl);
267  assert(I && "missing implementation");
268  R.addListener(llvm::make_unique<DFGASTReaderListener>(*I));
269 }
270 
271 /// FileMatchesDepCriteria - Determine whether the given Filename should be
272 /// considered as a dependency.
273 bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
274  SrcMgr::CharacteristicKind FileType) {
275  if (isSpecialFilename(Filename))
276  return false;
277 
278  if (IncludeSystemHeaders)
279  return true;
280 
281  return !isSystem(FileType);
282 }
283 
284 void DFGImpl::FileChanged(SourceLocation Loc,
285  FileChangeReason Reason,
287  FileID PrevFID) {
288  if (Reason != PPCallbacks::EnterFile)
289  return;
290 
291  // Dependency generation really does want to go all the way to the
292  // file entry for a source location to find out what is depended on.
293  // We do not want #line markers to affect dependency generation!
294  SourceManager &SM = PP->getSourceManager();
295 
296  const FileEntry *FE =
298  if (!FE) return;
299 
300  StringRef Filename = FE->getName();
301  if (!FileMatchesDepCriteria(Filename.data(), FileType))
302  return;
303 
304  AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
305 }
306 
307 void DFGImpl::FileSkipped(const FileEntry &SkippedFile,
308  const Token &FilenameTok,
309  SrcMgr::CharacteristicKind FileType) {
310  StringRef Filename = SkippedFile.getName();
311  if (!FileMatchesDepCriteria(Filename.data(), FileType))
312  return;
313 
314  AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
315 }
316 
317 void DFGImpl::InclusionDirective(SourceLocation HashLoc,
318  const Token &IncludeTok,
319  StringRef FileName,
320  bool IsAngled,
321  CharSourceRange FilenameRange,
322  const FileEntry *File,
323  StringRef SearchPath,
324  StringRef RelativePath,
325  const Module *Imported,
326  SrcMgr::CharacteristicKind FileType) {
327  if (!File) {
328  if (AddMissingHeaderDeps)
329  AddFilename(FileName);
330  else
331  SeenMissingHeader = true;
332  }
333 }
334 
335 void DFGImpl::HasInclude(SourceLocation Loc, StringRef SpelledFilename,
336  bool IsAngled, const FileEntry *File,
337  SrcMgr::CharacteristicKind FileType) {
338  if (!File)
339  return;
340  StringRef Filename = File->getName();
341  if (!FileMatchesDepCriteria(Filename.data(), FileType))
342  return;
343  AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
344 }
345 
346 bool DFGImpl::AddFilename(StringRef Filename) {
347  if (FilesSet.insert(Filename).second) {
348  Files.push_back(Filename);
349  return true;
350  }
351  return false;
352 }
353 
354 /// Print the filename, with escaping or quoting that accommodates the three
355 /// most likely tools that use dependency files: GNU Make, BSD Make, and
356 /// NMake/Jom.
357 ///
358 /// BSD Make is the simplest case: It does no escaping at all. This means
359 /// characters that are normally delimiters, i.e. space and # (the comment
360 /// character) simply aren't supported in filenames.
361 ///
362 /// GNU Make does allow space and # in filenames, but to avoid being treated
363 /// as a delimiter or comment, these must be escaped with a backslash. Because
364 /// backslash is itself the escape character, if a backslash appears in a
365 /// filename, it should be escaped as well. (As a special case, $ is escaped
366 /// as $$, which is the normal Make way to handle the $ character.)
367 /// For compatibility with BSD Make and historical practice, if GNU Make
368 /// un-escapes characters in a filename but doesn't find a match, it will
369 /// retry with the unmodified original string.
370 ///
371 /// GCC tries to accommodate both Make formats by escaping any space or #
372 /// characters in the original filename, but not escaping backslashes. The
373 /// apparent intent is so that filenames with backslashes will be handled
374 /// correctly by BSD Make, and by GNU Make in its fallback mode of using the
375 /// unmodified original string; filenames with # or space characters aren't
376 /// supported by BSD Make at all, but will be handled correctly by GNU Make
377 /// due to the escaping.
378 ///
379 /// A corner case that GCC gets only partly right is when the original filename
380 /// has a backslash immediately followed by space or #. GNU Make would expect
381 /// this backslash to be escaped; however GCC escapes the original backslash
382 /// only when followed by space, not #. It will therefore take a dependency
383 /// from a directive such as
384 /// #include "a\ b\#c.h"
385 /// and emit it as
386 /// a\\\ b\\#c.h
387 /// which GNU Make will interpret as
388 /// a\ b\
389 /// followed by a comment. Failing to find this file, it will fall back to the
390 /// original string, which probably doesn't exist either; in any case it won't
391 /// find
392 /// a\ b\#c.h
393 /// which is the actual filename specified by the include directive.
394 ///
395 /// Clang does what GCC does, rather than what GNU Make expects.
396 ///
397 /// NMake/Jom has a different set of scary characters, but wraps filespecs in
398 /// double-quotes to avoid misinterpreting them; see
399 /// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
400 /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
401 /// for Windows file-naming info.
402 static void PrintFilename(raw_ostream &OS, StringRef Filename,
403  DependencyOutputFormat OutputFormat) {
404  // Convert filename to platform native path
405  llvm::SmallString<256> NativePath;
406  llvm::sys::path::native(Filename.str(), NativePath);
407 
408  if (OutputFormat == DependencyOutputFormat::NMake) {
409  // Add quotes if needed. These are the characters listed as "special" to
410  // NMake, that are legal in a Windows filespec, and that could cause
411  // misinterpretation of the dependency string.
412  if (NativePath.find_first_of(" #${}^!") != StringRef::npos)
413  OS << '\"' << NativePath << '\"';
414  else
415  OS << NativePath;
416  return;
417  }
418  assert(OutputFormat == DependencyOutputFormat::Make);
419  for (unsigned i = 0, e = NativePath.size(); i != e; ++i) {
420  if (NativePath[i] == '#') // Handle '#' the broken gcc way.
421  OS << '\\';
422  else if (NativePath[i] == ' ') { // Handle space correctly.
423  OS << '\\';
424  unsigned j = i;
425  while (j > 0 && NativePath[--j] == '\\')
426  OS << '\\';
427  } else if (NativePath[i] == '$') // $ is escaped by $$.
428  OS << '$';
429  OS << NativePath[i];
430  }
431 }
432 
433 void DFGImpl::OutputDependencyFile() {
434  if (SeenMissingHeader) {
435  llvm::sys::fs::remove(OutputFile);
436  return;
437  }
438 
439  std::error_code EC;
440  llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
441  if (EC) {
442  PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
443  << EC.message();
444  return;
445  }
446 
447  // Write out the dependency targets, trying to avoid overly long
448  // lines when possible. We try our best to emit exactly the same
449  // dependency file as GCC (4.2), assuming the included files are the
450  // same.
451  const unsigned MaxColumns = 75;
452  unsigned Columns = 0;
453 
454  for (StringRef Target : Targets) {
455  unsigned N = Target.size();
456  if (Columns == 0) {
457  Columns += N;
458  } else if (Columns + N + 2 > MaxColumns) {
459  Columns = N + 2;
460  OS << " \\\n ";
461  } else {
462  Columns += N + 1;
463  OS << ' ';
464  }
465  // Targets already quoted as needed.
466  OS << Target;
467  }
468 
469  OS << ':';
470  Columns += 1;
471 
472  // Now add each dependency in the order it was seen, but avoiding
473  // duplicates.
474  for (StringRef File : Files) {
475  // Start a new line if this would exceed the column limit. Make
476  // sure to leave space for a trailing " \" in case we need to
477  // break the line on the next iteration.
478  unsigned N = File.size();
479  if (Columns + (N + 1) + 2 > MaxColumns) {
480  OS << " \\\n ";
481  Columns = 2;
482  }
483  OS << ' ';
484  PrintFilename(OS, File, OutputFormat);
485  Columns += N + 1;
486  }
487  OS << '\n';
488 
489  // Create phony targets if requested.
490  if (PhonyTarget && !Files.empty()) {
491  unsigned Index = 0;
492  for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
493  if (Index++ == InputFileIndex)
494  continue;
495  OS << '\n';
496  PrintFilename(OS, *I, OutputFormat);
497  OS << ":\n";
498  }
499  }
500 }
501 
502 bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
503  bool IsSystem, bool IsOverridden,
504  bool IsExplicitModule) {
505  assert(!IsSystem || needsSystemInputFileVisitation());
506  if (IsOverridden || IsExplicitModule)
507  return true;
508 
509  Parent.AddFilename(Filename);
510  return true;
511 }
512 
513 void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename,
515  if (Parent.includeModuleFiles())
516  Parent.AddFilename(Filename);
517 }
Defines the clang::FileManager interface and associated types.
An interface for collecting the dependencies of a compilation.
Definition: Utils.h:83
Defines the SourceManager interface.
unsigned IncludeModuleFiles
Include module file dependencies.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1292
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
Definition: SourceManager.h:78
ModuleMap & getModuleMap()
Retrieve the module map.
Definition: HeaderSearch.h:655
This interface provides a way to observe the actions of the preprocessor as it does its thing...
Definition: PPCallbacks.h:36
unsigned IncludeSystemHeaders
Include system header dependencies.
virtual bool needSystemDependencies()
Return true if system files should be passed to sawDependency().
Definition: Utils.h:102
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
Describes a module or submodule.
Definition: Module.h:65
void SetSuppressIncludeNotFoundError(bool Suppress)
Definition: Preprocessor.h:860
virtual void attachToASTReader(ASTReader &R)
HeaderSearch & getHeaderSearchInfo() const
Definition: Preprocessor.h:821
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
void addModuleMapCallbacks(std::unique_ptr< ModuleMapCallbacks > Callback)
Add a module map callback.
Definition: ModuleMap.h:412
Builds a depdenency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
Definition: Utils.h:119
NodeId Parent
Definition: ASTDiff.cpp:192
static DependencyFileGenerator * CreateAndAttachToPreprocessor(Preprocessor &PP, const DependencyOutputOptions &Opts)
ModuleKind
Specifies the kind of module that has been loaded.
Definition: Module.h:43
StringRef Filename
Definition: Format.cpp:1629
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...
static bool isSpecialFilename(StringRef Filename)
Represents a character-granular source range.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
virtual void finishedMainFile()
Called when the end of the main file is reached.
Definition: Utils.h:99
Defines the clang::Preprocessor interface.
A mechanism to observe the actions of the module map parser as it reads module map files...
Definition: ModuleMap.h:47
Record the location of an inclusion directive, such as an #include or #import statement.
const SourceManager & SM
Definition: Format.cpp:1490
SourceManager & getSourceManager() const
Definition: Preprocessor.h:819
Kind
void addListener(std::unique_ptr< ASTReaderListener > L)
Add an AST callback listener.
Definition: ASTReader.h:1582
void AttachToASTReader(ASTReader &R)
Encodes a location in the source.
StringRef getName() const
Definition: FileManager.h:86
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:60
DependencyOutputOptions - Options for controlling the compiler dependency file generation.
std::vector< std::string > ExtraDeps
A list of filenames to be used as extra dependencies for every target.
std::string OutputFile
The file to write dependency output to.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
DependencyOutputFormat OutputFormat
The format for the dependency file.
Dataflow Directional Tag Classes.
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:355
unsigned UsePhonyTargets
Include phony targets for each dependency, which can avoid some &#39;make&#39; problems.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:127
virtual void attachToPreprocessor(Preprocessor &PP)
Defines the PPCallbacks interface.
DiagnosticsEngine & getDiagnostics() const
Definition: Preprocessor.h:812
std::vector< std::string > Targets
A list of names to use as the targets in the dependency file; this list must contain at least one ent...
unsigned AddMissingHeaderDeps
Add missing headers to dependency list.
virtual bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsMissing)
Called when a new file is seen.
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...
DependencyOutputFormat
DependencyOutputFormat - Format for the compiler dependency file.
bool isSystem(CharacteristicKind CK)
Determine whether a file / directory characteristic is for system code.
Definition: SourceManager.h:83
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Definition: Preprocessor.h:908
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:125