clang  3.7.0
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/PPCallbacks.h"
22 #include "clang/Lex/Preprocessor.h"
24 #include "llvm/ADT/StringSet.h"
25 #include "llvm/ADT/StringSwitch.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/Path.h"
28 #include "llvm/Support/raw_ostream.h"
29 
30 using namespace clang;
31 
32 namespace {
33 struct DepCollectorPPCallbacks : public PPCallbacks {
34  DependencyCollector &DepCollector;
36  DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM)
37  : DepCollector(L), SM(SM) { }
38 
39  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
41  FileID PrevFID) override {
42  if (Reason != PPCallbacks::EnterFile)
43  return;
44 
45  // Dependency generation really does want to go all the way to the
46  // file entry for a source location to find out what is depended on.
47  // We do not want #line markers to affect dependency generation!
48  const FileEntry *FE =
50  if (!FE)
51  return;
52 
53  StringRef Filename = FE->getName();
54 
55  // Remove leading "./" (or ".//" or "././" etc.)
56  while (Filename.size() > 2 && Filename[0] == '.' &&
57  llvm::sys::path::is_separator(Filename[1])) {
58  Filename = Filename.substr(1);
59  while (llvm::sys::path::is_separator(Filename[0]))
60  Filename = Filename.substr(1);
61  }
62 
63  DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
64  FileType != SrcMgr::C_User,
65  /*IsModuleFile*/false, /*IsMissing*/false);
66  }
67 
68  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
69  StringRef FileName, bool IsAngled,
70  CharSourceRange FilenameRange, const FileEntry *File,
71  StringRef SearchPath, StringRef RelativePath,
72  const Module *Imported) override {
73  if (!File)
74  DepCollector.maybeAddDependency(FileName, /*FromModule*/false,
75  /*IsSystem*/false, /*IsModuleFile*/false,
76  /*IsMissing*/true);
77  // Files that actually exist are handled by FileChanged.
78  }
79 
80  void EndOfMainFile() override {
81  DepCollector.finishedMainFile();
82  }
83 };
84 
85 struct DepCollectorASTListener : public ASTReaderListener {
86  DependencyCollector &DepCollector;
87  DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
88  bool needsInputFileVisitation() override { return true; }
89  bool needsSystemInputFileVisitation() override {
90  return DepCollector.needSystemDependencies();
91  }
92  void visitModuleFile(StringRef Filename) override {
93  DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
94  /*IsSystem*/false, /*IsModuleFile*/true,
95  /*IsMissing*/false);
96  }
97  bool visitInputFile(StringRef Filename, bool IsSystem,
98  bool IsOverridden) override {
99  if (IsOverridden)
100  return true;
101 
102  DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem,
103  /*IsModuleFile*/false, /*IsMissing*/false);
104  return true;
105  }
106 };
107 } // end anonymous namespace
108 
109 void DependencyCollector::maybeAddDependency(StringRef Filename, bool FromModule,
110  bool IsSystem, bool IsModuleFile,
111  bool IsMissing) {
112  if (Seen.insert(Filename).second &&
113  sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
114  Dependencies.push_back(Filename);
115 }
116 
117 static bool isSpecialFilename(StringRef Filename) {
118  return llvm::StringSwitch<bool>(Filename)
119  .Case("<built-in>", true)
120  .Case("<stdin>", true)
121  .Default(false);
122 }
123 
124 bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
125  bool IsSystem, bool IsModuleFile,
126  bool IsMissing) {
127  return !isSpecialFilename(Filename) &&
128  (needSystemDependencies() || !IsSystem);
129 }
130 
133  PP.addPPCallbacks(
134  llvm::make_unique<DepCollectorPPCallbacks>(*this, PP.getSourceManager()));
135 }
137  R.addListener(llvm::make_unique<DepCollectorASTListener>(*this));
138 }
139 
140 namespace {
141 /// Private implementation for DependencyFileGenerator
142 class DFGImpl : public PPCallbacks {
143  std::vector<std::string> Files;
144  llvm::StringSet<> FilesSet;
145  const Preprocessor *PP;
146  std::string OutputFile;
147  std::vector<std::string> Targets;
148  bool IncludeSystemHeaders;
149  bool PhonyTarget;
150  bool AddMissingHeaderDeps;
151  bool SeenMissingHeader;
152  bool IncludeModuleFiles;
153  DependencyOutputFormat OutputFormat;
154 
155 private:
156  bool FileMatchesDepCriteria(const char *Filename,
157  SrcMgr::CharacteristicKind FileType);
158  void OutputDependencyFile();
159 
160 public:
161  DFGImpl(const Preprocessor *_PP, const DependencyOutputOptions &Opts)
162  : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets),
163  IncludeSystemHeaders(Opts.IncludeSystemHeaders),
164  PhonyTarget(Opts.UsePhonyTargets),
165  AddMissingHeaderDeps(Opts.AddMissingHeaderDeps),
166  SeenMissingHeader(false),
167  IncludeModuleFiles(Opts.IncludeModuleFiles),
168  OutputFormat(Opts.OutputFormat) {}
169 
170  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
172  FileID PrevFID) override;
173  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
174  StringRef FileName, bool IsAngled,
175  CharSourceRange FilenameRange, const FileEntry *File,
176  StringRef SearchPath, StringRef RelativePath,
177  const Module *Imported) override;
178 
179  void EndOfMainFile() override {
180  OutputDependencyFile();
181  }
182 
183  void AddFilename(StringRef Filename);
184  bool includeSystemHeaders() const { return IncludeSystemHeaders; }
185  bool includeModuleFiles() const { return IncludeModuleFiles; }
186 };
187 
188 class DFGASTReaderListener : public ASTReaderListener {
189  DFGImpl &Parent;
190 public:
191  DFGASTReaderListener(DFGImpl &Parent)
192  : Parent(Parent) { }
193  bool needsInputFileVisitation() override { return true; }
194  bool needsSystemInputFileVisitation() override {
195  return Parent.includeSystemHeaders();
196  }
197  void visitModuleFile(StringRef Filename) override;
198  bool visitInputFile(StringRef Filename, bool isSystem,
199  bool isOverridden) override;
200 };
201 }
202 
203 DependencyFileGenerator::DependencyFileGenerator(void *Impl)
204 : Impl(Impl) { }
205 
208 
209  if (Opts.Targets.empty()) {
210  PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
211  return nullptr;
212  }
213 
214  // Disable the "file not found" diagnostic if the -MG option was given.
215  if (Opts.AddMissingHeaderDeps)
217 
218  DFGImpl *Callback = new DFGImpl(&PP, Opts);
219  PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callback));
220  return new DependencyFileGenerator(Callback);
221 }
222 
224  DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl);
225  assert(I && "missing implementation");
226  R.addListener(llvm::make_unique<DFGASTReaderListener>(*I));
227 }
228 
229 /// FileMatchesDepCriteria - Determine whether the given Filename should be
230 /// considered as a dependency.
231 bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
232  SrcMgr::CharacteristicKind FileType) {
233  if (isSpecialFilename(Filename))
234  return false;
235 
236  if (IncludeSystemHeaders)
237  return true;
238 
239  return FileType == SrcMgr::C_User;
240 }
241 
242 void DFGImpl::FileChanged(SourceLocation Loc,
243  FileChangeReason Reason,
245  FileID PrevFID) {
246  if (Reason != PPCallbacks::EnterFile)
247  return;
248 
249  // Dependency generation really does want to go all the way to the
250  // file entry for a source location to find out what is depended on.
251  // We do not want #line markers to affect dependency generation!
252  SourceManager &SM = PP->getSourceManager();
253 
254  const FileEntry *FE =
256  if (!FE) return;
257 
258  StringRef Filename = FE->getName();
259  if (!FileMatchesDepCriteria(Filename.data(), FileType))
260  return;
261 
262  // Remove leading "./" (or ".//" or "././" etc.)
263  while (Filename.size() > 2 && Filename[0] == '.' &&
264  llvm::sys::path::is_separator(Filename[1])) {
265  Filename = Filename.substr(1);
266  while (llvm::sys::path::is_separator(Filename[0]))
267  Filename = Filename.substr(1);
268  }
269 
270  AddFilename(Filename);
271 }
272 
273 void DFGImpl::InclusionDirective(SourceLocation HashLoc,
274  const Token &IncludeTok,
275  StringRef FileName,
276  bool IsAngled,
277  CharSourceRange FilenameRange,
278  const FileEntry *File,
279  StringRef SearchPath,
280  StringRef RelativePath,
281  const Module *Imported) {
282  if (!File) {
283  if (AddMissingHeaderDeps)
284  AddFilename(FileName);
285  else
286  SeenMissingHeader = true;
287  }
288 }
289 
290 void DFGImpl::AddFilename(StringRef Filename) {
291  if (FilesSet.insert(Filename).second)
292  Files.push_back(Filename);
293 }
294 
295 /// Print the filename, with escaping or quoting that accommodates the three
296 /// most likely tools that use dependency files: GNU Make, BSD Make, and
297 /// NMake/Jom.
298 ///
299 /// BSD Make is the simplest case: It does no escaping at all. This means
300 /// characters that are normally delimiters, i.e. space and # (the comment
301 /// character) simply aren't supported in filenames.
302 ///
303 /// GNU Make does allow space and # in filenames, but to avoid being treated
304 /// as a delimiter or comment, these must be escaped with a backslash. Because
305 /// backslash is itself the escape character, if a backslash appears in a
306 /// filename, it should be escaped as well. (As a special case, $ is escaped
307 /// as $$, which is the normal Make way to handle the $ character.)
308 /// For compatibility with BSD Make and historical practice, if GNU Make
309 /// un-escapes characters in a filename but doesn't find a match, it will
310 /// retry with the unmodified original string.
311 ///
312 /// GCC tries to accommodate both Make formats by escaping any space or #
313 /// characters in the original filename, but not escaping backslashes. The
314 /// apparent intent is so that filenames with backslashes will be handled
315 /// correctly by BSD Make, and by GNU Make in its fallback mode of using the
316 /// unmodified original string; filenames with # or space characters aren't
317 /// supported by BSD Make at all, but will be handled correctly by GNU Make
318 /// due to the escaping.
319 ///
320 /// A corner case that GCC gets only partly right is when the original filename
321 /// has a backslash immediately followed by space or #. GNU Make would expect
322 /// this backslash to be escaped; however GCC escapes the original backslash
323 /// only when followed by space, not #. It will therefore take a dependency
324 /// from a directive such as
325 /// #include "a\ b\#c.h"
326 /// and emit it as
327 /// a\\\ b\\#c.h
328 /// which GNU Make will interpret as
329 /// a\ b\
330 /// followed by a comment. Failing to find this file, it will fall back to the
331 /// original string, which probably doesn't exist either; in any case it won't
332 /// find
333 /// a\ b\#c.h
334 /// which is the actual filename specified by the include directive.
335 ///
336 /// Clang does what GCC does, rather than what GNU Make expects.
337 ///
338 /// NMake/Jom has a different set of scary characters, but wraps filespecs in
339 /// double-quotes to avoid misinterpreting them; see
340 /// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
341 /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
342 /// for Windows file-naming info.
343 static void PrintFilename(raw_ostream &OS, StringRef Filename,
344  DependencyOutputFormat OutputFormat) {
345  if (OutputFormat == DependencyOutputFormat::NMake) {
346  // Add quotes if needed. These are the characters listed as "special" to
347  // NMake, that are legal in a Windows filespec, and that could cause
348  // misinterpretation of the dependency string.
349  if (Filename.find_first_of(" #${}^!") != StringRef::npos)
350  OS << '\"' << Filename << '\"';
351  else
352  OS << Filename;
353  return;
354  }
355  assert(OutputFormat == DependencyOutputFormat::Make);
356  for (unsigned i = 0, e = Filename.size(); i != e; ++i) {
357  if (Filename[i] == '#') // Handle '#' the broken gcc way.
358  OS << '\\';
359  else if (Filename[i] == ' ') { // Handle space correctly.
360  OS << '\\';
361  unsigned j = i;
362  while (j > 0 && Filename[--j] == '\\')
363  OS << '\\';
364  } else if (Filename[i] == '$') // $ is escaped by $$.
365  OS << '$';
366  OS << Filename[i];
367  }
368 }
369 
370 void DFGImpl::OutputDependencyFile() {
371  if (SeenMissingHeader) {
372  llvm::sys::fs::remove(OutputFile);
373  return;
374  }
375 
376  std::error_code EC;
377  llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
378  if (EC) {
379  PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
380  << EC.message();
381  return;
382  }
383 
384  // Write out the dependency targets, trying to avoid overly long
385  // lines when possible. We try our best to emit exactly the same
386  // dependency file as GCC (4.2), assuming the included files are the
387  // same.
388  const unsigned MaxColumns = 75;
389  unsigned Columns = 0;
390 
391  for (std::vector<std::string>::iterator
392  I = Targets.begin(), E = Targets.end(); I != E; ++I) {
393  unsigned N = I->length();
394  if (Columns == 0) {
395  Columns += N;
396  } else if (Columns + N + 2 > MaxColumns) {
397  Columns = N + 2;
398  OS << " \\\n ";
399  } else {
400  Columns += N + 1;
401  OS << ' ';
402  }
403  // Targets already quoted as needed.
404  OS << *I;
405  }
406 
407  OS << ':';
408  Columns += 1;
409 
410  // Now add each dependency in the order it was seen, but avoiding
411  // duplicates.
412  for (std::vector<std::string>::iterator I = Files.begin(),
413  E = Files.end(); I != E; ++I) {
414  // Start a new line if this would exceed the column limit. Make
415  // sure to leave space for a trailing " \" in case we need to
416  // break the line on the next iteration.
417  unsigned N = I->length();
418  if (Columns + (N + 1) + 2 > MaxColumns) {
419  OS << " \\\n ";
420  Columns = 2;
421  }
422  OS << ' ';
423  PrintFilename(OS, *I, OutputFormat);
424  Columns += N + 1;
425  }
426  OS << '\n';
427 
428  // Create phony targets if requested.
429  if (PhonyTarget && !Files.empty()) {
430  // Skip the first entry, this is always the input file itself.
431  for (std::vector<std::string>::iterator I = Files.begin() + 1,
432  E = Files.end(); I != E; ++I) {
433  OS << '\n';
434  PrintFilename(OS, *I, OutputFormat);
435  OS << ":\n";
436  }
437  }
438 }
439 
440 bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
441  bool IsSystem, bool IsOverridden) {
442  assert(!IsSystem || needsSystemInputFileVisitation());
443  if (IsOverridden)
444  return true;
445 
446  Parent.AddFilename(Filename);
447  return true;
448 }
449 
450 void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename) {
451  if (Parent.includeModuleFiles())
452  Parent.AddFilename(Filename);
453 }
SourceManager & getSourceManager() const
Definition: Preprocessor.h:682
Defines the clang::FileManager interface and associated types.
Defines the SourceManager interface.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1118
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
Definition: SourceManager.h:78
This interface provides a way to observe the actions of the preprocessor as it does its thing...
Definition: PPCallbacks.h:38
virtual bool needSystemDependencies()
Return true if system files should be passed to sawDependency().
Definition: Utils.h:93
Describes a module or submodule.
Definition: Basic/Module.h:49
void SetSuppressIncludeNotFoundError(bool Suppress)
Definition: Preprocessor.h:726
void attachToASTReader(ASTReader &R)
static DependencyFileGenerator * CreateAndAttachToPreprocessor(Preprocessor &PP, const DependencyOutputOptions &Opts)
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
SourceManager & SM
void maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsMissing)
static bool isSpecialFilename(StringRef Filename)
Represents a character-granular source range.
MatchFinder::MatchCallback * Callback
Defines the clang::Preprocessor interface.
Record the location of an inclusion directive, such as an #include or #import statement.
#define false
Definition: stdbool.h:33
void addListener(std::unique_ptr< ASTReaderListener > L)
Add an AST callback listener.
Definition: ASTReader.h:1373
void AttachToASTReader(ASTReader &R)
const char * getName() const
Definition: FileManager.h:84
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:53
DiagnosticsEngine & getDiagnostics() const
Definition: Preprocessor.h:676
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:302
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:101
void attachToPreprocessor(Preprocessor &PP)
Defines the PPCallbacks interface.
std::vector< std::string > Targets
unsigned AddMissingHeaderDeps
Add missing headers to dependency list.
virtual bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsMissing)
static void PrintFilename(raw_ostream &OS, StringRef Filename, DependencyOutputFormat OutputFormat)
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
DependencyOutputFormat
DependencyOutputFormat - Format for the compiler dependency file.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Definition: Preprocessor.h:773
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:96