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