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