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