DependencyFile.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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/PPCallbacks.h"
  21. #include "clang/Lex/Preprocessor.h"
  22. #include "clang/Serialization/ASTReader.h"
  23. #include "llvm/ADT/StringSet.h"
  24. #include "llvm/ADT/StringSwitch.h"
  25. #include "llvm/Support/FileSystem.h"
  26. #include "llvm/Support/Path.h"
  27. #include "llvm/Support/raw_ostream.h"
  28. using namespace clang;
  29. namespace {
  30. struct DepCollectorPPCallbacks : public PPCallbacks {
  31. DependencyCollector &DepCollector;
  32. SourceManager &SM;
  33. DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM)
  34. : DepCollector(L), SM(SM) { }
  35. void FileChanged(SourceLocation Loc, FileChangeReason Reason,
  36. SrcMgr::CharacteristicKind FileType,
  37. FileID PrevFID) override {
  38. if (Reason != PPCallbacks::EnterFile)
  39. return;
  40. // Dependency generation really does want to go all the way to the
  41. // file entry for a source location to find out what is depended on.
  42. // We do not want #line markers to affect dependency generation!
  43. const FileEntry *FE =
  44. SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
  45. if (!FE)
  46. return;
  47. StringRef Filename = FE->getName();
  48. // Remove leading "./" (or ".//" or "././" etc.)
  49. while (Filename.size() > 2 && Filename[0] == '.' &&
  50. llvm::sys::path::is_separator(Filename[1])) {
  51. Filename = Filename.substr(1);
  52. while (llvm::sys::path::is_separator(Filename[0]))
  53. Filename = Filename.substr(1);
  54. }
  55. DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
  56. FileType != SrcMgr::C_User,
  57. /*IsModuleFile*/false, /*IsMissing*/false);
  58. }
  59. void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
  60. StringRef FileName, bool IsAngled,
  61. CharSourceRange FilenameRange, const FileEntry *File,
  62. StringRef SearchPath, StringRef RelativePath,
  63. const Module *Imported) override {
  64. if (!File)
  65. DepCollector.maybeAddDependency(FileName, /*FromModule*/false,
  66. /*IsSystem*/false, /*IsModuleFile*/false,
  67. /*IsMissing*/true);
  68. // Files that actually exist are handled by FileChanged.
  69. }
  70. void EndOfMainFile() override {
  71. DepCollector.finishedMainFile();
  72. }
  73. };
  74. struct DepCollectorASTListener : public ASTReaderListener {
  75. DependencyCollector &DepCollector;
  76. DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
  77. bool needsInputFileVisitation() override { return true; }
  78. bool needsSystemInputFileVisitation() override {
  79. return DepCollector.needSystemDependencies();
  80. }
  81. void visitModuleFile(StringRef Filename) override {
  82. DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
  83. /*IsSystem*/false, /*IsModuleFile*/true,
  84. /*IsMissing*/false);
  85. }
  86. bool visitInputFile(StringRef Filename, bool IsSystem,
  87. bool IsOverridden) override {
  88. if (IsOverridden)
  89. return true;
  90. DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem,
  91. /*IsModuleFile*/false, /*IsMissing*/false);
  92. return true;
  93. }
  94. };
  95. } // end anonymous namespace
  96. void DependencyCollector::maybeAddDependency(StringRef Filename, bool FromModule,
  97. bool IsSystem, bool IsModuleFile,
  98. bool IsMissing) {
  99. if (Seen.insert(Filename).second &&
  100. sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
  101. Dependencies.push_back(Filename);
  102. }
  103. static bool isSpecialFilename(StringRef Filename) {
  104. return llvm::StringSwitch<bool>(Filename)
  105. .Case("<built-in>", true)
  106. .Case("<stdin>", true)
  107. .Default(false);
  108. }
  109. bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
  110. bool IsSystem, bool IsModuleFile,
  111. bool IsMissing) {
  112. return !isSpecialFilename(Filename) &&
  113. (needSystemDependencies() || !IsSystem);
  114. }
  115. DependencyCollector::~DependencyCollector() { }
  116. void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
  117. PP.addPPCallbacks(
  118. llvm::make_unique<DepCollectorPPCallbacks>(*this, PP.getSourceManager()));
  119. }
  120. void DependencyCollector::attachToASTReader(ASTReader &R) {
  121. R.addListener(llvm::make_unique<DepCollectorASTListener>(*this));
  122. }
  123. namespace {
  124. /// Private implementation for DependencyFileGenerator
  125. class DFGImpl : public PPCallbacks {
  126. std::vector<std::string> Files;
  127. llvm::StringSet<> FilesSet;
  128. const Preprocessor *PP;
  129. std::string OutputFile;
  130. std::vector<std::string> Targets;
  131. bool IncludeSystemHeaders;
  132. bool PhonyTarget;
  133. bool AddMissingHeaderDeps;
  134. bool SeenMissingHeader;
  135. bool IncludeModuleFiles;
  136. DependencyOutputFormat OutputFormat;
  137. private:
  138. bool FileMatchesDepCriteria(const char *Filename,
  139. SrcMgr::CharacteristicKind FileType);
  140. void OutputDependencyFile();
  141. public:
  142. DFGImpl(const Preprocessor *_PP, const DependencyOutputOptions &Opts)
  143. : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets),
  144. IncludeSystemHeaders(Opts.IncludeSystemHeaders),
  145. PhonyTarget(Opts.UsePhonyTargets),
  146. AddMissingHeaderDeps(Opts.AddMissingHeaderDeps),
  147. SeenMissingHeader(false),
  148. IncludeModuleFiles(Opts.IncludeModuleFiles),
  149. OutputFormat(Opts.OutputFormat) {}
  150. void FileChanged(SourceLocation Loc, FileChangeReason Reason,
  151. SrcMgr::CharacteristicKind FileType,
  152. FileID PrevFID) override;
  153. void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
  154. StringRef FileName, bool IsAngled,
  155. CharSourceRange FilenameRange, const FileEntry *File,
  156. StringRef SearchPath, StringRef RelativePath,
  157. const Module *Imported) override;
  158. void EndOfMainFile() override {
  159. OutputDependencyFile();
  160. }
  161. void AddFilename(StringRef Filename);
  162. bool includeSystemHeaders() const { return IncludeSystemHeaders; }
  163. bool includeModuleFiles() const { return IncludeModuleFiles; }
  164. };
  165. class DFGASTReaderListener : public ASTReaderListener {
  166. DFGImpl &Parent;
  167. public:
  168. DFGASTReaderListener(DFGImpl &Parent)
  169. : Parent(Parent) { }
  170. bool needsInputFileVisitation() override { return true; }
  171. bool needsSystemInputFileVisitation() override {
  172. return Parent.includeSystemHeaders();
  173. }
  174. void visitModuleFile(StringRef Filename) override;
  175. bool visitInputFile(StringRef Filename, bool isSystem,
  176. bool isOverridden) override;
  177. };
  178. }
  179. DependencyFileGenerator::DependencyFileGenerator(void *Impl)
  180. : Impl(Impl) { }
  181. DependencyFileGenerator *DependencyFileGenerator::CreateAndAttachToPreprocessor(
  182. clang::Preprocessor &PP, const clang::DependencyOutputOptions &Opts) {
  183. if (Opts.Targets.empty()) {
  184. PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
  185. return nullptr;
  186. }
  187. // Disable the "file not found" diagnostic if the -MG option was given.
  188. if (Opts.AddMissingHeaderDeps)
  189. PP.SetSuppressIncludeNotFoundError(true);
  190. DFGImpl *Callback = new DFGImpl(&PP, Opts);
  191. PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callback));
  192. return new DependencyFileGenerator(Callback);
  193. }
  194. void DependencyFileGenerator::AttachToASTReader(ASTReader &R) {
  195. DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl);
  196. assert(I && "missing implementation");
  197. R.addListener(llvm::make_unique<DFGASTReaderListener>(*I));
  198. }
  199. /// FileMatchesDepCriteria - Determine whether the given Filename should be
  200. /// considered as a dependency.
  201. bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
  202. SrcMgr::CharacteristicKind FileType) {
  203. if (isSpecialFilename(Filename))
  204. return false;
  205. if (IncludeSystemHeaders)
  206. return true;
  207. return FileType == SrcMgr::C_User;
  208. }
  209. void DFGImpl::FileChanged(SourceLocation Loc,
  210. FileChangeReason Reason,
  211. SrcMgr::CharacteristicKind FileType,
  212. FileID PrevFID) {
  213. if (Reason != PPCallbacks::EnterFile)
  214. return;
  215. // Dependency generation really does want to go all the way to the
  216. // file entry for a source location to find out what is depended on.
  217. // We do not want #line markers to affect dependency generation!
  218. SourceManager &SM = PP->getSourceManager();
  219. const FileEntry *FE =
  220. SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
  221. if (!FE) return;
  222. StringRef Filename = FE->getName();
  223. if (!FileMatchesDepCriteria(Filename.data(), FileType))
  224. return;
  225. // Remove leading "./" (or ".//" or "././" etc.)
  226. while (Filename.size() > 2 && Filename[0] == '.' &&
  227. llvm::sys::path::is_separator(Filename[1])) {
  228. Filename = Filename.substr(1);
  229. while (llvm::sys::path::is_separator(Filename[0]))
  230. Filename = Filename.substr(1);
  231. }
  232. AddFilename(Filename);
  233. }
  234. void DFGImpl::InclusionDirective(SourceLocation HashLoc,
  235. const Token &IncludeTok,
  236. StringRef FileName,
  237. bool IsAngled,
  238. CharSourceRange FilenameRange,
  239. const FileEntry *File,
  240. StringRef SearchPath,
  241. StringRef RelativePath,
  242. const Module *Imported) {
  243. if (!File) {
  244. if (AddMissingHeaderDeps)
  245. AddFilename(FileName);
  246. else
  247. SeenMissingHeader = true;
  248. }
  249. }
  250. void DFGImpl::AddFilename(StringRef Filename) {
  251. if (FilesSet.insert(Filename).second)
  252. Files.push_back(Filename);
  253. }
  254. /// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or
  255. /// other scary characters. NMake/Jom has a different set of scary characters,
  256. /// but wraps filespecs in double-quotes to avoid misinterpreting them;
  257. /// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
  258. /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
  259. /// for Windows file-naming info.
  260. static void PrintFilename(raw_ostream &OS, StringRef Filename,
  261. DependencyOutputFormat OutputFormat) {
  262. if (OutputFormat == DependencyOutputFormat::NMake) {
  263. // Add quotes if needed. These are the characters listed as "special" to
  264. // NMake, that are legal in a Windows filespec, and that could cause
  265. // misinterpretation of the dependency string.
  266. if (Filename.find_first_of(" #${}^!") != StringRef::npos)
  267. OS << '\"' << Filename << '\"';
  268. else
  269. OS << Filename;
  270. return;
  271. }
  272. for (unsigned i = 0, e = Filename.size(); i != e; ++i) {
  273. if (Filename[i] == ' ' || Filename[i] == '#')
  274. OS << '\\';
  275. else if (Filename[i] == '$') // $ is escaped by $$.
  276. OS << '$';
  277. OS << Filename[i];
  278. }
  279. }
  280. void DFGImpl::OutputDependencyFile() {
  281. if (SeenMissingHeader) {
  282. llvm::sys::fs::remove(OutputFile);
  283. return;
  284. }
  285. std::error_code EC;
  286. llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
  287. if (EC) {
  288. PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
  289. << EC.message();
  290. return;
  291. }
  292. // Write out the dependency targets, trying to avoid overly long
  293. // lines when possible. We try our best to emit exactly the same
  294. // dependency file as GCC (4.2), assuming the included files are the
  295. // same.
  296. const unsigned MaxColumns = 75;
  297. unsigned Columns = 0;
  298. for (std::vector<std::string>::iterator
  299. I = Targets.begin(), E = Targets.end(); I != E; ++I) {
  300. unsigned N = I->length();
  301. if (Columns == 0) {
  302. Columns += N;
  303. } else if (Columns + N + 2 > MaxColumns) {
  304. Columns = N + 2;
  305. OS << " \\\n ";
  306. } else {
  307. Columns += N + 1;
  308. OS << ' ';
  309. }
  310. // Targets already quoted as needed.
  311. OS << *I;
  312. }
  313. OS << ':';
  314. Columns += 1;
  315. // Now add each dependency in the order it was seen, but avoiding
  316. // duplicates.
  317. for (std::vector<std::string>::iterator I = Files.begin(),
  318. E = Files.end(); I != E; ++I) {
  319. // Start a new line if this would exceed the column limit. Make
  320. // sure to leave space for a trailing " \" in case we need to
  321. // break the line on the next iteration.
  322. unsigned N = I->length();
  323. if (Columns + (N + 1) + 2 > MaxColumns) {
  324. OS << " \\\n ";
  325. Columns = 2;
  326. }
  327. OS << ' ';
  328. PrintFilename(OS, *I, OutputFormat);
  329. Columns += N + 1;
  330. }
  331. OS << '\n';
  332. // Create phony targets if requested.
  333. if (PhonyTarget && !Files.empty()) {
  334. // Skip the first entry, this is always the input file itself.
  335. for (std::vector<std::string>::iterator I = Files.begin() + 1,
  336. E = Files.end(); I != E; ++I) {
  337. OS << '\n';
  338. PrintFilename(OS, *I, OutputFormat);
  339. OS << ":\n";
  340. }
  341. }
  342. }
  343. bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
  344. bool IsSystem, bool IsOverridden) {
  345. assert(!IsSystem || needsSystemInputFileVisitation());
  346. if (IsOverridden)
  347. return true;
  348. Parent.AddFilename(Filename);
  349. return true;
  350. }
  351. void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename) {
  352. if (Parent.includeModuleFiles())
  353. Parent.AddFilename(Filename);
  354. }