DependencyFile.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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. #include "clang/Frontend/Utils.h"
  13. #include "clang/Basic/FileManager.h"
  14. #include "clang/Basic/SourceManager.h"
  15. #include "clang/Frontend/DependencyOutputOptions.h"
  16. #include "clang/Frontend/FrontendDiagnostic.h"
  17. #include "clang/Lex/DirectoryLookup.h"
  18. #include "clang/Lex/ModuleMap.h"
  19. #include "clang/Lex/PPCallbacks.h"
  20. #include "clang/Lex/Preprocessor.h"
  21. #include "clang/Serialization/ASTReader.h"
  22. #include "llvm/ADT/StringSet.h"
  23. #include "llvm/ADT/StringSwitch.h"
  24. #include "llvm/Support/FileSystem.h"
  25. #include "llvm/Support/Path.h"
  26. #include "llvm/Support/raw_ostream.h"
  27. using namespace clang;
  28. namespace {
  29. struct DepCollectorPPCallbacks : public PPCallbacks {
  30. DependencyCollector &DepCollector;
  31. SourceManager &SM;
  32. DiagnosticsEngine &Diags;
  33. DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM,
  34. DiagnosticsEngine &Diags)
  35. : DepCollector(L), SM(SM), Diags(Diags) {}
  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. if (Optional<StringRef> Filename = SM.getNonBuiltinFilenameForID(
  45. SM.getFileID(SM.getExpansionLoc(Loc))))
  46. DepCollector.maybeAddDependency(
  47. llvm::sys::path::remove_leading_dotslash(*Filename),
  48. /*FromModule*/ false, isSystem(FileType), /*IsModuleFile*/ false,
  49. /*IsMissing*/ false);
  50. }
  51. void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
  52. SrcMgr::CharacteristicKind FileType) override {
  53. StringRef Filename =
  54. llvm::sys::path::remove_leading_dotslash(SkippedFile.getName());
  55. DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
  56. /*IsSystem=*/isSystem(FileType),
  57. /*IsModuleFile=*/false,
  58. /*IsMissing=*/false);
  59. }
  60. void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
  61. StringRef FileName, bool IsAngled,
  62. CharSourceRange FilenameRange, const FileEntry *File,
  63. StringRef SearchPath, StringRef RelativePath,
  64. const Module *Imported,
  65. SrcMgr::CharacteristicKind FileType) override {
  66. if (!File)
  67. DepCollector.maybeAddDependency(FileName, /*FromModule*/false,
  68. /*IsSystem*/false, /*IsModuleFile*/false,
  69. /*IsMissing*/true);
  70. // Files that actually exist are handled by FileChanged.
  71. }
  72. void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
  73. Optional<FileEntryRef> File,
  74. SrcMgr::CharacteristicKind FileType) override {
  75. if (!File)
  76. return;
  77. StringRef Filename =
  78. llvm::sys::path::remove_leading_dotslash(File->getName());
  79. DepCollector.maybeAddDependency(Filename, /*FromModule=*/false,
  80. /*IsSystem=*/isSystem(FileType),
  81. /*IsModuleFile=*/false,
  82. /*IsMissing=*/false);
  83. }
  84. void EndOfMainFile() override { DepCollector.finishedMainFile(Diags); }
  85. };
  86. struct DepCollectorMMCallbacks : public ModuleMapCallbacks {
  87. DependencyCollector &DepCollector;
  88. DepCollectorMMCallbacks(DependencyCollector &DC) : DepCollector(DC) {}
  89. void moduleMapFileRead(SourceLocation Loc, const FileEntry &Entry,
  90. bool IsSystem) override {
  91. StringRef Filename = Entry.getName();
  92. DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
  93. /*IsSystem*/IsSystem,
  94. /*IsModuleFile*/false,
  95. /*IsMissing*/false);
  96. }
  97. };
  98. struct DepCollectorASTListener : public ASTReaderListener {
  99. DependencyCollector &DepCollector;
  100. DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
  101. bool needsInputFileVisitation() override { return true; }
  102. bool needsSystemInputFileVisitation() override {
  103. return DepCollector.needSystemDependencies();
  104. }
  105. void visitModuleFile(StringRef Filename,
  106. serialization::ModuleKind Kind) override {
  107. DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
  108. /*IsSystem*/false, /*IsModuleFile*/true,
  109. /*IsMissing*/false);
  110. }
  111. bool visitInputFile(StringRef Filename, bool IsSystem,
  112. bool IsOverridden, bool IsExplicitModule) override {
  113. if (IsOverridden || IsExplicitModule)
  114. return true;
  115. DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem,
  116. /*IsModuleFile*/false, /*IsMissing*/false);
  117. return true;
  118. }
  119. };
  120. } // end anonymous namespace
  121. void DependencyCollector::maybeAddDependency(StringRef Filename,
  122. bool FromModule, bool IsSystem,
  123. bool IsModuleFile,
  124. bool IsMissing) {
  125. if (sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
  126. addDependency(Filename);
  127. }
  128. bool DependencyCollector::addDependency(StringRef Filename) {
  129. StringRef SearchPath;
  130. #ifdef _WIN32
  131. // Make the search insensitive to case and separators.
  132. llvm::SmallString<256> TmpPath = Filename;
  133. llvm::sys::path::native(TmpPath);
  134. std::transform(TmpPath.begin(), TmpPath.end(), TmpPath.begin(), ::tolower);
  135. SearchPath = TmpPath.str();
  136. #else
  137. SearchPath = Filename;
  138. #endif
  139. if (Seen.insert(SearchPath).second) {
  140. Dependencies.push_back(std::string(Filename));
  141. return true;
  142. }
  143. return false;
  144. }
  145. static bool isSpecialFilename(StringRef Filename) {
  146. return llvm::StringSwitch<bool>(Filename)
  147. .Case("<built-in>", true)
  148. .Case("<stdin>", true)
  149. .Default(false);
  150. }
  151. bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
  152. bool IsSystem, bool IsModuleFile,
  153. bool IsMissing) {
  154. return !isSpecialFilename(Filename) &&
  155. (needSystemDependencies() || !IsSystem);
  156. }
  157. DependencyCollector::~DependencyCollector() { }
  158. void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
  159. PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(
  160. *this, PP.getSourceManager(), PP.getDiagnostics()));
  161. PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
  162. std::make_unique<DepCollectorMMCallbacks>(*this));
  163. }
  164. void DependencyCollector::attachToASTReader(ASTReader &R) {
  165. R.addListener(std::make_unique<DepCollectorASTListener>(*this));
  166. }
  167. DependencyFileGenerator::DependencyFileGenerator(
  168. const DependencyOutputOptions &Opts)
  169. : OutputFile(Opts.OutputFile), Targets(Opts.Targets),
  170. IncludeSystemHeaders(Opts.IncludeSystemHeaders),
  171. PhonyTarget(Opts.UsePhonyTargets),
  172. AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false),
  173. IncludeModuleFiles(Opts.IncludeModuleFiles),
  174. OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
  175. for (const auto &ExtraDep : Opts.ExtraDeps) {
  176. if (addDependency(ExtraDep.first))
  177. ++InputFileIndex;
  178. }
  179. }
  180. void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) {
  181. // Disable the "file not found" diagnostic if the -MG option was given.
  182. if (AddMissingHeaderDeps)
  183. PP.SetSuppressIncludeNotFoundError(true);
  184. DependencyCollector::attachToPreprocessor(PP);
  185. }
  186. bool DependencyFileGenerator::sawDependency(StringRef Filename, bool FromModule,
  187. bool IsSystem, bool IsModuleFile,
  188. bool IsMissing) {
  189. if (IsMissing) {
  190. // Handle the case of missing file from an inclusion directive.
  191. if (AddMissingHeaderDeps)
  192. return true;
  193. SeenMissingHeader = true;
  194. return false;
  195. }
  196. if (IsModuleFile && !IncludeModuleFiles)
  197. return false;
  198. if (isSpecialFilename(Filename))
  199. return false;
  200. if (IncludeSystemHeaders)
  201. return true;
  202. return !IsSystem;
  203. }
  204. void DependencyFileGenerator::finishedMainFile(DiagnosticsEngine &Diags) {
  205. outputDependencyFile(Diags);
  206. }
  207. /// Print the filename, with escaping or quoting that accommodates the three
  208. /// most likely tools that use dependency files: GNU Make, BSD Make, and
  209. /// NMake/Jom.
  210. ///
  211. /// BSD Make is the simplest case: It does no escaping at all. This means
  212. /// characters that are normally delimiters, i.e. space and # (the comment
  213. /// character) simply aren't supported in filenames.
  214. ///
  215. /// GNU Make does allow space and # in filenames, but to avoid being treated
  216. /// as a delimiter or comment, these must be escaped with a backslash. Because
  217. /// backslash is itself the escape character, if a backslash appears in a
  218. /// filename, it should be escaped as well. (As a special case, $ is escaped
  219. /// as $$, which is the normal Make way to handle the $ character.)
  220. /// For compatibility with BSD Make and historical practice, if GNU Make
  221. /// un-escapes characters in a filename but doesn't find a match, it will
  222. /// retry with the unmodified original string.
  223. ///
  224. /// GCC tries to accommodate both Make formats by escaping any space or #
  225. /// characters in the original filename, but not escaping backslashes. The
  226. /// apparent intent is so that filenames with backslashes will be handled
  227. /// correctly by BSD Make, and by GNU Make in its fallback mode of using the
  228. /// unmodified original string; filenames with # or space characters aren't
  229. /// supported by BSD Make at all, but will be handled correctly by GNU Make
  230. /// due to the escaping.
  231. ///
  232. /// A corner case that GCC gets only partly right is when the original filename
  233. /// has a backslash immediately followed by space or #. GNU Make would expect
  234. /// this backslash to be escaped; however GCC escapes the original backslash
  235. /// only when followed by space, not #. It will therefore take a dependency
  236. /// from a directive such as
  237. /// #include "a\ b\#c.h"
  238. /// and emit it as
  239. /// a\\\ b\\#c.h
  240. /// which GNU Make will interpret as
  241. /// a\ b\
  242. /// followed by a comment. Failing to find this file, it will fall back to the
  243. /// original string, which probably doesn't exist either; in any case it won't
  244. /// find
  245. /// a\ b\#c.h
  246. /// which is the actual filename specified by the include directive.
  247. ///
  248. /// Clang does what GCC does, rather than what GNU Make expects.
  249. ///
  250. /// NMake/Jom has a different set of scary characters, but wraps filespecs in
  251. /// double-quotes to avoid misinterpreting them; see
  252. /// https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx for NMake info,
  253. /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
  254. /// for Windows file-naming info.
  255. static void PrintFilename(raw_ostream &OS, StringRef Filename,
  256. DependencyOutputFormat OutputFormat) {
  257. // Convert filename to platform native path
  258. llvm::SmallString<256> NativePath;
  259. llvm::sys::path::native(Filename.str(), NativePath);
  260. if (OutputFormat == DependencyOutputFormat::NMake) {
  261. // Add quotes if needed. These are the characters listed as "special" to
  262. // NMake, that are legal in a Windows filespec, and that could cause
  263. // misinterpretation of the dependency string.
  264. if (NativePath.find_first_of(" #${}^!") != StringRef::npos)
  265. OS << '\"' << NativePath << '\"';
  266. else
  267. OS << NativePath;
  268. return;
  269. }
  270. assert(OutputFormat == DependencyOutputFormat::Make);
  271. for (unsigned i = 0, e = NativePath.size(); i != e; ++i) {
  272. if (NativePath[i] == '#') // Handle '#' the broken gcc way.
  273. OS << '\\';
  274. else if (NativePath[i] == ' ') { // Handle space correctly.
  275. OS << '\\';
  276. unsigned j = i;
  277. while (j > 0 && NativePath[--j] == '\\')
  278. OS << '\\';
  279. } else if (NativePath[i] == '$') // $ is escaped by $$.
  280. OS << '$';
  281. OS << NativePath[i];
  282. }
  283. }
  284. void DependencyFileGenerator::outputDependencyFile(DiagnosticsEngine &Diags) {
  285. if (SeenMissingHeader) {
  286. llvm::sys::fs::remove(OutputFile);
  287. return;
  288. }
  289. std::error_code EC;
  290. llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF);
  291. if (EC) {
  292. Diags.Report(diag::err_fe_error_opening) << OutputFile << EC.message();
  293. return;
  294. }
  295. outputDependencyFile(OS);
  296. }
  297. void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
  298. // Write out the dependency targets, trying to avoid overly long
  299. // lines when possible. We try our best to emit exactly the same
  300. // dependency file as GCC (4.2), assuming the included files are the
  301. // same.
  302. const unsigned MaxColumns = 75;
  303. unsigned Columns = 0;
  304. for (StringRef Target : Targets) {
  305. unsigned N = Target.size();
  306. if (Columns == 0) {
  307. Columns += N;
  308. } else if (Columns + N + 2 > MaxColumns) {
  309. Columns = N + 2;
  310. OS << " \\\n ";
  311. } else {
  312. Columns += N + 1;
  313. OS << ' ';
  314. }
  315. // Targets already quoted as needed.
  316. OS << Target;
  317. }
  318. OS << ':';
  319. Columns += 1;
  320. // Now add each dependency in the order it was seen, but avoiding
  321. // duplicates.
  322. ArrayRef<std::string> Files = getDependencies();
  323. for (StringRef File : Files) {
  324. // Start a new line if this would exceed the column limit. Make
  325. // sure to leave space for a trailing " \" in case we need to
  326. // break the line on the next iteration.
  327. unsigned N = File.size();
  328. if (Columns + (N + 1) + 2 > MaxColumns) {
  329. OS << " \\\n ";
  330. Columns = 2;
  331. }
  332. OS << ' ';
  333. PrintFilename(OS, File, OutputFormat);
  334. Columns += N + 1;
  335. }
  336. OS << '\n';
  337. // Create phony targets if requested.
  338. if (PhonyTarget && !Files.empty()) {
  339. unsigned Index = 0;
  340. for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
  341. if (Index++ == InputFileIndex)
  342. continue;
  343. OS << '\n';
  344. PrintFilename(OS, *I, OutputFormat);
  345. OS << ":\n";
  346. }
  347. }
  348. }