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 "clang/Serialization/ASTReader.h" 24 #include "llvm/ADT/StringSet.h" 25 #include "llvm/Support/FileSystem.h" 26 #include "llvm/Support/Path.h" 27 #include "llvm/Support/raw_ostream.h" 28 29 using namespace clang; 30 31 namespace { 32 struct DepCollectorPPCallbacks : public PPCallbacks { 33 DependencyCollector &DepCollector; 34 SourceManager &SM; 35 DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM) 36 : DepCollector(L), SM(SM) { } 37 38 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 39 SrcMgr::CharacteristicKind FileType, 40 FileID PrevFID) override { 41 if (Reason != PPCallbacks::EnterFile) 42 return; 43 44 // Dependency generation really does want to go all the way to the 45 // file entry for a source location to find out what is depended on. 46 // We do not want #line markers to affect dependency generation! 47 const FileEntry *FE = 48 SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc))); 49 if (!FE) 50 return; 51 52 StringRef Filename = FE->getName(); 53 54 // Remove leading "./" (or ".//" or "././" etc.) 55 while (Filename.size() > 2 && Filename[0] == '.' && 56 llvm::sys::path::is_separator(Filename[1])) { 57 Filename = Filename.substr(1); 58 while (llvm::sys::path::is_separator(Filename[0])) 59 Filename = Filename.substr(1); 60 } 61 62 DepCollector.maybeAddDependency(Filename, /*FromModule*/false, 63 FileType != SrcMgr::C_User, 64 /*IsModuleFile*/false, /*IsMissing*/false); 65 } 66 67 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 68 StringRef FileName, bool IsAngled, 69 CharSourceRange FilenameRange, const FileEntry *File, 70 StringRef SearchPath, StringRef RelativePath, 71 const Module *Imported) override { 72 if (!File) 73 DepCollector.maybeAddDependency(FileName, /*FromModule*/false, 74 /*IsSystem*/false, /*IsModuleFile*/false, 75 /*IsMissing*/true); 76 // Files that actually exist are handled by FileChanged. 77 } 78 79 void EndOfMainFile() override { 80 DepCollector.finishedMainFile(); 81 } 82 }; 83 84 struct DepCollectorASTListener : public ASTReaderListener { 85 DependencyCollector &DepCollector; 86 DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { } 87 bool needsInputFileVisitation() override { return true; } 88 bool needsSystemInputFileVisitation() override { 89 return DepCollector.needSystemDependencies(); 90 } 91 void visitModuleFile(StringRef Filename) override { 92 DepCollector.maybeAddDependency(Filename, /*FromModule*/true, 93 /*IsSystem*/false, /*IsModuleFile*/true, 94 /*IsMissing*/false); 95 } 96 bool visitInputFile(StringRef Filename, bool IsSystem, 97 bool IsOverridden) override { 98 if (IsOverridden) 99 return true; 100 101 DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem, 102 /*IsModuleFile*/false, /*IsMissing*/false); 103 return true; 104 } 105 }; 106 } // end anonymous namespace 107 108 void DependencyCollector::maybeAddDependency(StringRef Filename, bool FromModule, 109 bool IsSystem, bool IsModuleFile, 110 bool IsMissing) { 111 if (Seen.insert(Filename) && 112 sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing)) 113 Dependencies.push_back(Filename); 114 } 115 116 bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule, 117 bool IsSystem, bool IsModuleFile, 118 bool IsMissing) { 119 return Filename != "<built-in>" && (needSystemDependencies() || !IsSystem); 120 } 121 122 DependencyCollector::~DependencyCollector() { } 123 void DependencyCollector::attachToPreprocessor(Preprocessor &PP) { 124 PP.addPPCallbacks( 125 llvm::make_unique<DepCollectorPPCallbacks>(*this, PP.getSourceManager())); 126 } 127 void DependencyCollector::attachToASTReader(ASTReader &R) { 128 R.addListener(llvm::make_unique<DepCollectorASTListener>(*this)); 129 } 130 131 namespace { 132 /// Private implementation for DependencyFileGenerator 133 class DFGImpl : public PPCallbacks { 134 std::vector<std::string> Files; 135 llvm::StringSet<> FilesSet; 136 const Preprocessor *PP; 137 std::string OutputFile; 138 std::vector<std::string> Targets; 139 bool IncludeSystemHeaders; 140 bool PhonyTarget; 141 bool AddMissingHeaderDeps; 142 bool SeenMissingHeader; 143 bool IncludeModuleFiles; 144 private: 145 bool FileMatchesDepCriteria(const char *Filename, 146 SrcMgr::CharacteristicKind FileType); 147 void OutputDependencyFile(); 148 149 public: 150 DFGImpl(const Preprocessor *_PP, const DependencyOutputOptions &Opts) 151 : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets), 152 IncludeSystemHeaders(Opts.IncludeSystemHeaders), 153 PhonyTarget(Opts.UsePhonyTargets), 154 AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), 155 SeenMissingHeader(false), 156 IncludeModuleFiles(Opts.IncludeModuleFiles) {} 157 158 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 159 SrcMgr::CharacteristicKind FileType, 160 FileID PrevFID) override; 161 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 162 StringRef FileName, bool IsAngled, 163 CharSourceRange FilenameRange, const FileEntry *File, 164 StringRef SearchPath, StringRef RelativePath, 165 const Module *Imported) override; 166 167 void EndOfMainFile() override { 168 OutputDependencyFile(); 169 } 170 171 void AddFilename(StringRef Filename); 172 bool includeSystemHeaders() const { return IncludeSystemHeaders; } 173 bool includeModuleFiles() const { return IncludeModuleFiles; } 174 }; 175 176 class DFGASTReaderListener : public ASTReaderListener { 177 DFGImpl &Parent; 178 public: 179 DFGASTReaderListener(DFGImpl &Parent) 180 : Parent(Parent) { } 181 bool needsInputFileVisitation() override { return true; } 182 bool needsSystemInputFileVisitation() override { 183 return Parent.includeSystemHeaders(); 184 } 185 void visitModuleFile(StringRef Filename) override; 186 bool visitInputFile(StringRef Filename, bool isSystem, 187 bool isOverridden) override; 188 }; 189 } 190 191 DependencyFileGenerator::DependencyFileGenerator(void *Impl) 192 : Impl(Impl) { } 193 194 DependencyFileGenerator *DependencyFileGenerator::CreateAndAttachToPreprocessor( 195 clang::Preprocessor &PP, const clang::DependencyOutputOptions &Opts) { 196 197 if (Opts.Targets.empty()) { 198 PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT); 199 return nullptr; 200 } 201 202 // Disable the "file not found" diagnostic if the -MG option was given. 203 if (Opts.AddMissingHeaderDeps) 204 PP.SetSuppressIncludeNotFoundError(true); 205 206 DFGImpl *Callback = new DFGImpl(&PP, Opts); 207 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callback)); 208 return new DependencyFileGenerator(Callback); 209 } 210 211 void DependencyFileGenerator::AttachToASTReader(ASTReader &R) { 212 DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl); 213 assert(I && "missing implementation"); 214 R.addListener(llvm::make_unique<DFGASTReaderListener>(*I)); 215 } 216 217 /// FileMatchesDepCriteria - Determine whether the given Filename should be 218 /// considered as a dependency. 219 bool DFGImpl::FileMatchesDepCriteria(const char *Filename, 220 SrcMgr::CharacteristicKind FileType) { 221 if (strcmp("<built-in>", Filename) == 0) 222 return false; 223 224 if (IncludeSystemHeaders) 225 return true; 226 227 return FileType == SrcMgr::C_User; 228 } 229 230 void DFGImpl::FileChanged(SourceLocation Loc, 231 FileChangeReason Reason, 232 SrcMgr::CharacteristicKind FileType, 233 FileID PrevFID) { 234 if (Reason != PPCallbacks::EnterFile) 235 return; 236 237 // Dependency generation really does want to go all the way to the 238 // file entry for a source location to find out what is depended on. 239 // We do not want #line markers to affect dependency generation! 240 SourceManager &SM = PP->getSourceManager(); 241 242 const FileEntry *FE = 243 SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc))); 244 if (!FE) return; 245 246 StringRef Filename = FE->getName(); 247 if (!FileMatchesDepCriteria(Filename.data(), FileType)) 248 return; 249 250 // Remove leading "./" (or ".//" or "././" etc.) 251 while (Filename.size() > 2 && Filename[0] == '.' && 252 llvm::sys::path::is_separator(Filename[1])) { 253 Filename = Filename.substr(1); 254 while (llvm::sys::path::is_separator(Filename[0])) 255 Filename = Filename.substr(1); 256 } 257 258 AddFilename(Filename); 259 } 260 261 void DFGImpl::InclusionDirective(SourceLocation HashLoc, 262 const Token &IncludeTok, 263 StringRef FileName, 264 bool IsAngled, 265 CharSourceRange FilenameRange, 266 const FileEntry *File, 267 StringRef SearchPath, 268 StringRef RelativePath, 269 const Module *Imported) { 270 if (!File) { 271 if (AddMissingHeaderDeps) 272 AddFilename(FileName); 273 else 274 SeenMissingHeader = true; 275 } 276 } 277 278 void DFGImpl::AddFilename(StringRef Filename) { 279 if (FilesSet.insert(Filename)) 280 Files.push_back(Filename); 281 } 282 283 /// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or 284 /// other scary characters. 285 static void PrintFilename(raw_ostream &OS, StringRef Filename) { 286 for (unsigned i = 0, e = Filename.size(); i != e; ++i) { 287 if (Filename[i] == ' ' || Filename[i] == '#') 288 OS << '\\'; 289 else if (Filename[i] == '$') // $ is escaped by $$. 290 OS << '$'; 291 OS << Filename[i]; 292 } 293 } 294 295 void DFGImpl::OutputDependencyFile() { 296 if (SeenMissingHeader) { 297 llvm::sys::fs::remove(OutputFile); 298 return; 299 } 300 301 std::error_code EC; 302 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text); 303 if (EC) { 304 PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile 305 << EC.message(); 306 return; 307 } 308 309 // Write out the dependency targets, trying to avoid overly long 310 // lines when possible. We try our best to emit exactly the same 311 // dependency file as GCC (4.2), assuming the included files are the 312 // same. 313 const unsigned MaxColumns = 75; 314 unsigned Columns = 0; 315 316 for (std::vector<std::string>::iterator 317 I = Targets.begin(), E = Targets.end(); I != E; ++I) { 318 unsigned N = I->length(); 319 if (Columns == 0) { 320 Columns += N; 321 } else if (Columns + N + 2 > MaxColumns) { 322 Columns = N + 2; 323 OS << " \\\n "; 324 } else { 325 Columns += N + 1; 326 OS << ' '; 327 } 328 // Targets already quoted as needed. 329 OS << *I; 330 } 331 332 OS << ':'; 333 Columns += 1; 334 335 // Now add each dependency in the order it was seen, but avoiding 336 // duplicates. 337 for (std::vector<std::string>::iterator I = Files.begin(), 338 E = Files.end(); I != E; ++I) { 339 // Start a new line if this would exceed the column limit. Make 340 // sure to leave space for a trailing " \" in case we need to 341 // break the line on the next iteration. 342 unsigned N = I->length(); 343 if (Columns + (N + 1) + 2 > MaxColumns) { 344 OS << " \\\n "; 345 Columns = 2; 346 } 347 OS << ' '; 348 PrintFilename(OS, *I); 349 Columns += N + 1; 350 } 351 OS << '\n'; 352 353 // Create phony targets if requested. 354 if (PhonyTarget && !Files.empty()) { 355 // Skip the first entry, this is always the input file itself. 356 for (std::vector<std::string>::iterator I = Files.begin() + 1, 357 E = Files.end(); I != E; ++I) { 358 OS << '\n'; 359 PrintFilename(OS, *I); 360 OS << ":\n"; 361 } 362 } 363 } 364 365 bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename, 366 bool IsSystem, bool IsOverridden) { 367 assert(!IsSystem || needsSystemInputFileVisitation()); 368 if (IsOverridden) 369 return true; 370 371 Parent.AddFilename(Filename); 372 return true; 373 } 374 375 void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename) { 376 if (Parent.includeModuleFiles()) 377 Parent.AddFilename(Filename); 378 } 379