DependencyFile.cpp 18 KB

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