DependencyFile.cpp 7.4 KB

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