DependencyFile.cpp 5.6 KB

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