DependencyFile.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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/Support/FileSystem.h"
  25. #include "llvm/Support/Path.h"
  26. #include "llvm/Support/raw_ostream.h"
  27. using namespace clang;
  28. namespace {
  29. /// Private implementation for DependencyFileGenerator
  30. class DFGImpl : public PPCallbacks {
  31. std::vector<std::string> Files;
  32. llvm::StringSet<> FilesSet;
  33. const Preprocessor *PP;
  34. std::string OutputFile;
  35. std::vector<std::string> Targets;
  36. bool IncludeSystemHeaders;
  37. bool PhonyTarget;
  38. bool AddMissingHeaderDeps;
  39. bool SeenMissingHeader;
  40. bool IncludeModuleFiles;
  41. private:
  42. bool FileMatchesDepCriteria(const char *Filename,
  43. SrcMgr::CharacteristicKind FileType);
  44. void OutputDependencyFile();
  45. public:
  46. DFGImpl(const Preprocessor *_PP, const DependencyOutputOptions &Opts)
  47. : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets),
  48. IncludeSystemHeaders(Opts.IncludeSystemHeaders),
  49. PhonyTarget(Opts.UsePhonyTargets),
  50. AddMissingHeaderDeps(Opts.AddMissingHeaderDeps),
  51. SeenMissingHeader(false),
  52. IncludeModuleFiles(Opts.IncludeModuleFiles) {}
  53. void FileChanged(SourceLocation Loc, FileChangeReason Reason,
  54. SrcMgr::CharacteristicKind FileType,
  55. FileID PrevFID) override;
  56. void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
  57. StringRef FileName, bool IsAngled,
  58. CharSourceRange FilenameRange, const FileEntry *File,
  59. StringRef SearchPath, StringRef RelativePath,
  60. const Module *Imported) override;
  61. void EndOfMainFile() override {
  62. OutputDependencyFile();
  63. }
  64. void AddFilename(StringRef Filename);
  65. bool includeSystemHeaders() const { return IncludeSystemHeaders; }
  66. bool includeModuleFiles() const { return IncludeModuleFiles; }
  67. };
  68. class DFGASTReaderListener : public ASTReaderListener {
  69. DFGImpl &Parent;
  70. public:
  71. DFGASTReaderListener(DFGImpl &Parent)
  72. : Parent(Parent) { }
  73. bool needsInputFileVisitation() override { return true; }
  74. bool needsSystemInputFileVisitation() override {
  75. return Parent.includeSystemHeaders();
  76. }
  77. void visitModuleFile(StringRef Filename) override;
  78. bool visitInputFile(StringRef Filename, bool isSystem,
  79. bool isOverridden) override;
  80. };
  81. }
  82. DependencyFileGenerator::DependencyFileGenerator(void *Impl)
  83. : Impl(Impl) { }
  84. DependencyFileGenerator *DependencyFileGenerator::CreateAndAttachToPreprocessor(
  85. clang::Preprocessor &PP, const clang::DependencyOutputOptions &Opts) {
  86. if (Opts.Targets.empty()) {
  87. PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
  88. return nullptr;
  89. }
  90. // Disable the "file not found" diagnostic if the -MG option was given.
  91. if (Opts.AddMissingHeaderDeps)
  92. PP.SetSuppressIncludeNotFoundError(true);
  93. DFGImpl *Callback = new DFGImpl(&PP, Opts);
  94. PP.addPPCallbacks(Callback); // PP owns the Callback
  95. return new DependencyFileGenerator(Callback);
  96. }
  97. void DependencyFileGenerator::AttachToASTReader(ASTReader &R) {
  98. DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl);
  99. assert(I && "missing implementation");
  100. R.addListener(new DFGASTReaderListener(*I));
  101. }
  102. /// FileMatchesDepCriteria - Determine whether the given Filename should be
  103. /// considered as a dependency.
  104. bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
  105. SrcMgr::CharacteristicKind FileType) {
  106. if (strcmp("<built-in>", Filename) == 0)
  107. return false;
  108. if (IncludeSystemHeaders)
  109. return true;
  110. return FileType == SrcMgr::C_User;
  111. }
  112. void DFGImpl::FileChanged(SourceLocation Loc,
  113. FileChangeReason Reason,
  114. SrcMgr::CharacteristicKind FileType,
  115. FileID PrevFID) {
  116. if (Reason != PPCallbacks::EnterFile)
  117. return;
  118. // Dependency generation really does want to go all the way to the
  119. // file entry for a source location to find out what is depended on.
  120. // We do not want #line markers to affect dependency generation!
  121. SourceManager &SM = PP->getSourceManager();
  122. const FileEntry *FE =
  123. SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
  124. if (!FE) return;
  125. StringRef Filename = FE->getName();
  126. if (!FileMatchesDepCriteria(Filename.data(), FileType))
  127. return;
  128. // Remove leading "./" (or ".//" or "././" etc.)
  129. while (Filename.size() > 2 && Filename[0] == '.' &&
  130. llvm::sys::path::is_separator(Filename[1])) {
  131. Filename = Filename.substr(1);
  132. while (llvm::sys::path::is_separator(Filename[0]))
  133. Filename = Filename.substr(1);
  134. }
  135. AddFilename(Filename);
  136. }
  137. void DFGImpl::InclusionDirective(SourceLocation HashLoc,
  138. const Token &IncludeTok,
  139. StringRef FileName,
  140. bool IsAngled,
  141. CharSourceRange FilenameRange,
  142. const FileEntry *File,
  143. StringRef SearchPath,
  144. StringRef RelativePath,
  145. const Module *Imported) {
  146. if (!File) {
  147. if (AddMissingHeaderDeps)
  148. AddFilename(FileName);
  149. else
  150. SeenMissingHeader = true;
  151. }
  152. }
  153. void DFGImpl::AddFilename(StringRef Filename) {
  154. if (FilesSet.insert(Filename))
  155. Files.push_back(Filename);
  156. }
  157. /// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or
  158. /// other scary characters.
  159. static void PrintFilename(raw_ostream &OS, StringRef Filename) {
  160. for (unsigned i = 0, e = Filename.size(); i != e; ++i) {
  161. if (Filename[i] == ' ' || Filename[i] == '#')
  162. OS << '\\';
  163. else if (Filename[i] == '$') // $ is escaped by $$.
  164. OS << '$';
  165. OS << Filename[i];
  166. }
  167. }
  168. void DFGImpl::OutputDependencyFile() {
  169. if (SeenMissingHeader) {
  170. llvm::sys::fs::remove(OutputFile);
  171. return;
  172. }
  173. std::string Err;
  174. llvm::raw_fd_ostream OS(OutputFile.c_str(), Err, llvm::sys::fs::F_Text);
  175. if (!Err.empty()) {
  176. PP->getDiagnostics().Report(diag::err_fe_error_opening)
  177. << OutputFile << Err;
  178. return;
  179. }
  180. // Write out the dependency targets, trying to avoid overly long
  181. // lines when possible. We try our best to emit exactly the same
  182. // dependency file as GCC (4.2), assuming the included files are the
  183. // same.
  184. const unsigned MaxColumns = 75;
  185. unsigned Columns = 0;
  186. for (std::vector<std::string>::iterator
  187. I = Targets.begin(), E = Targets.end(); I != E; ++I) {
  188. unsigned N = I->length();
  189. if (Columns == 0) {
  190. Columns += N;
  191. } else if (Columns + N + 2 > MaxColumns) {
  192. Columns = N + 2;
  193. OS << " \\\n ";
  194. } else {
  195. Columns += N + 1;
  196. OS << ' ';
  197. }
  198. // Targets already quoted as needed.
  199. OS << *I;
  200. }
  201. OS << ':';
  202. Columns += 1;
  203. // Now add each dependency in the order it was seen, but avoiding
  204. // duplicates.
  205. for (std::vector<std::string>::iterator I = Files.begin(),
  206. E = Files.end(); I != E; ++I) {
  207. // Start a new line if this would exceed the column limit. Make
  208. // sure to leave space for a trailing " \" in case we need to
  209. // break the line on the next iteration.
  210. unsigned N = I->length();
  211. if (Columns + (N + 1) + 2 > MaxColumns) {
  212. OS << " \\\n ";
  213. Columns = 2;
  214. }
  215. OS << ' ';
  216. PrintFilename(OS, *I);
  217. Columns += N + 1;
  218. }
  219. OS << '\n';
  220. // Create phony targets if requested.
  221. if (PhonyTarget && !Files.empty()) {
  222. // Skip the first entry, this is always the input file itself.
  223. for (std::vector<std::string>::iterator I = Files.begin() + 1,
  224. E = Files.end(); I != E; ++I) {
  225. OS << '\n';
  226. PrintFilename(OS, *I);
  227. OS << ":\n";
  228. }
  229. }
  230. }
  231. bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
  232. bool IsSystem, bool IsOverridden) {
  233. assert(!IsSystem || needsSystemInputFileVisitation());
  234. if (IsOverridden)
  235. return true;
  236. Parent.AddFilename(Filename);
  237. return true;
  238. }
  239. void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename) {
  240. if (Parent.includeModuleFiles())
  241. Parent.AddFilename(Filename);
  242. }