clang API Documentation
00001 //===--- DependencyFile.cpp - Generate dependency file --------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This code generates dependency files. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "clang/Frontend/Utils.h" 00015 #include "clang/Basic/FileManager.h" 00016 #include "clang/Basic/SourceManager.h" 00017 #include "clang/Frontend/DependencyOutputOptions.h" 00018 #include "clang/Frontend/FrontendDiagnostic.h" 00019 #include "clang/Lex/DirectoryLookup.h" 00020 #include "clang/Lex/LexDiagnostic.h" 00021 #include "clang/Lex/PPCallbacks.h" 00022 #include "clang/Lex/Preprocessor.h" 00023 #include "clang/Serialization/ASTReader.h" 00024 #include "llvm/ADT/StringSet.h" 00025 #include "llvm/ADT/StringSwitch.h" 00026 #include "llvm/Support/FileSystem.h" 00027 #include "llvm/Support/Path.h" 00028 #include "llvm/Support/raw_ostream.h" 00029 00030 using namespace clang; 00031 00032 namespace { 00033 struct DepCollectorPPCallbacks : public PPCallbacks { 00034 DependencyCollector &DepCollector; 00035 SourceManager &SM; 00036 DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM) 00037 : DepCollector(L), SM(SM) { } 00038 00039 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 00040 SrcMgr::CharacteristicKind FileType, 00041 FileID PrevFID) override { 00042 if (Reason != PPCallbacks::EnterFile) 00043 return; 00044 00045 // Dependency generation really does want to go all the way to the 00046 // file entry for a source location to find out what is depended on. 00047 // We do not want #line markers to affect dependency generation! 00048 const FileEntry *FE = 00049 SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc))); 00050 if (!FE) 00051 return; 00052 00053 StringRef Filename = FE->getName(); 00054 00055 // Remove leading "./" (or ".//" or "././" etc.) 00056 while (Filename.size() > 2 && Filename[0] == '.' && 00057 llvm::sys::path::is_separator(Filename[1])) { 00058 Filename = Filename.substr(1); 00059 while (llvm::sys::path::is_separator(Filename[0])) 00060 Filename = Filename.substr(1); 00061 } 00062 00063 DepCollector.maybeAddDependency(Filename, /*FromModule*/false, 00064 FileType != SrcMgr::C_User, 00065 /*IsModuleFile*/false, /*IsMissing*/false); 00066 } 00067 00068 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 00069 StringRef FileName, bool IsAngled, 00070 CharSourceRange FilenameRange, const FileEntry *File, 00071 StringRef SearchPath, StringRef RelativePath, 00072 const Module *Imported) override { 00073 if (!File) 00074 DepCollector.maybeAddDependency(FileName, /*FromModule*/false, 00075 /*IsSystem*/false, /*IsModuleFile*/false, 00076 /*IsMissing*/true); 00077 // Files that actually exist are handled by FileChanged. 00078 } 00079 00080 void EndOfMainFile() override { 00081 DepCollector.finishedMainFile(); 00082 } 00083 }; 00084 00085 struct DepCollectorASTListener : public ASTReaderListener { 00086 DependencyCollector &DepCollector; 00087 DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { } 00088 bool needsInputFileVisitation() override { return true; } 00089 bool needsSystemInputFileVisitation() override { 00090 return DepCollector.needSystemDependencies(); 00091 } 00092 void visitModuleFile(StringRef Filename) override { 00093 DepCollector.maybeAddDependency(Filename, /*FromModule*/true, 00094 /*IsSystem*/false, /*IsModuleFile*/true, 00095 /*IsMissing*/false); 00096 } 00097 bool visitInputFile(StringRef Filename, bool IsSystem, 00098 bool IsOverridden) override { 00099 if (IsOverridden) 00100 return true; 00101 00102 DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem, 00103 /*IsModuleFile*/false, /*IsMissing*/false); 00104 return true; 00105 } 00106 }; 00107 } // end anonymous namespace 00108 00109 void DependencyCollector::maybeAddDependency(StringRef Filename, bool FromModule, 00110 bool IsSystem, bool IsModuleFile, 00111 bool IsMissing) { 00112 if (Seen.insert(Filename) && 00113 sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing)) 00114 Dependencies.push_back(Filename); 00115 } 00116 00117 static bool isSpecialFilename(StringRef Filename) { 00118 return llvm::StringSwitch<bool>(Filename) 00119 .Case("<built-in>", true) 00120 .Case("<stdin>", true) 00121 .Default(false); 00122 } 00123 00124 bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule, 00125 bool IsSystem, bool IsModuleFile, 00126 bool IsMissing) { 00127 return !isSpecialFilename(Filename) && 00128 (needSystemDependencies() || !IsSystem); 00129 } 00130 00131 DependencyCollector::~DependencyCollector() { } 00132 void DependencyCollector::attachToPreprocessor(Preprocessor &PP) { 00133 PP.addPPCallbacks( 00134 llvm::make_unique<DepCollectorPPCallbacks>(*this, PP.getSourceManager())); 00135 } 00136 void DependencyCollector::attachToASTReader(ASTReader &R) { 00137 R.addListener(llvm::make_unique<DepCollectorASTListener>(*this)); 00138 } 00139 00140 namespace { 00141 /// Private implementation for DependencyFileGenerator 00142 class DFGImpl : public PPCallbacks { 00143 std::vector<std::string> Files; 00144 llvm::StringSet<> FilesSet; 00145 const Preprocessor *PP; 00146 std::string OutputFile; 00147 std::vector<std::string> Targets; 00148 bool IncludeSystemHeaders; 00149 bool PhonyTarget; 00150 bool AddMissingHeaderDeps; 00151 bool SeenMissingHeader; 00152 bool IncludeModuleFiles; 00153 private: 00154 bool FileMatchesDepCriteria(const char *Filename, 00155 SrcMgr::CharacteristicKind FileType); 00156 void OutputDependencyFile(); 00157 00158 public: 00159 DFGImpl(const Preprocessor *_PP, const DependencyOutputOptions &Opts) 00160 : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets), 00161 IncludeSystemHeaders(Opts.IncludeSystemHeaders), 00162 PhonyTarget(Opts.UsePhonyTargets), 00163 AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), 00164 SeenMissingHeader(false), 00165 IncludeModuleFiles(Opts.IncludeModuleFiles) {} 00166 00167 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 00168 SrcMgr::CharacteristicKind FileType, 00169 FileID PrevFID) override; 00170 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 00171 StringRef FileName, bool IsAngled, 00172 CharSourceRange FilenameRange, const FileEntry *File, 00173 StringRef SearchPath, StringRef RelativePath, 00174 const Module *Imported) override; 00175 00176 void EndOfMainFile() override { 00177 OutputDependencyFile(); 00178 } 00179 00180 void AddFilename(StringRef Filename); 00181 bool includeSystemHeaders() const { return IncludeSystemHeaders; } 00182 bool includeModuleFiles() const { return IncludeModuleFiles; } 00183 }; 00184 00185 class DFGASTReaderListener : public ASTReaderListener { 00186 DFGImpl &Parent; 00187 public: 00188 DFGASTReaderListener(DFGImpl &Parent) 00189 : Parent(Parent) { } 00190 bool needsInputFileVisitation() override { return true; } 00191 bool needsSystemInputFileVisitation() override { 00192 return Parent.includeSystemHeaders(); 00193 } 00194 void visitModuleFile(StringRef Filename) override; 00195 bool visitInputFile(StringRef Filename, bool isSystem, 00196 bool isOverridden) override; 00197 }; 00198 } 00199 00200 DependencyFileGenerator::DependencyFileGenerator(void *Impl) 00201 : Impl(Impl) { } 00202 00203 DependencyFileGenerator *DependencyFileGenerator::CreateAndAttachToPreprocessor( 00204 clang::Preprocessor &PP, const clang::DependencyOutputOptions &Opts) { 00205 00206 if (Opts.Targets.empty()) { 00207 PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT); 00208 return nullptr; 00209 } 00210 00211 // Disable the "file not found" diagnostic if the -MG option was given. 00212 if (Opts.AddMissingHeaderDeps) 00213 PP.SetSuppressIncludeNotFoundError(true); 00214 00215 DFGImpl *Callback = new DFGImpl(&PP, Opts); 00216 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callback)); 00217 return new DependencyFileGenerator(Callback); 00218 } 00219 00220 void DependencyFileGenerator::AttachToASTReader(ASTReader &R) { 00221 DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl); 00222 assert(I && "missing implementation"); 00223 R.addListener(llvm::make_unique<DFGASTReaderListener>(*I)); 00224 } 00225 00226 /// FileMatchesDepCriteria - Determine whether the given Filename should be 00227 /// considered as a dependency. 00228 bool DFGImpl::FileMatchesDepCriteria(const char *Filename, 00229 SrcMgr::CharacteristicKind FileType) { 00230 if (isSpecialFilename(Filename)) 00231 return false; 00232 00233 if (IncludeSystemHeaders) 00234 return true; 00235 00236 return FileType == SrcMgr::C_User; 00237 } 00238 00239 void DFGImpl::FileChanged(SourceLocation Loc, 00240 FileChangeReason Reason, 00241 SrcMgr::CharacteristicKind FileType, 00242 FileID PrevFID) { 00243 if (Reason != PPCallbacks::EnterFile) 00244 return; 00245 00246 // Dependency generation really does want to go all the way to the 00247 // file entry for a source location to find out what is depended on. 00248 // We do not want #line markers to affect dependency generation! 00249 SourceManager &SM = PP->getSourceManager(); 00250 00251 const FileEntry *FE = 00252 SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc))); 00253 if (!FE) return; 00254 00255 StringRef Filename = FE->getName(); 00256 if (!FileMatchesDepCriteria(Filename.data(), FileType)) 00257 return; 00258 00259 // Remove leading "./" (or ".//" or "././" etc.) 00260 while (Filename.size() > 2 && Filename[0] == '.' && 00261 llvm::sys::path::is_separator(Filename[1])) { 00262 Filename = Filename.substr(1); 00263 while (llvm::sys::path::is_separator(Filename[0])) 00264 Filename = Filename.substr(1); 00265 } 00266 00267 AddFilename(Filename); 00268 } 00269 00270 void DFGImpl::InclusionDirective(SourceLocation HashLoc, 00271 const Token &IncludeTok, 00272 StringRef FileName, 00273 bool IsAngled, 00274 CharSourceRange FilenameRange, 00275 const FileEntry *File, 00276 StringRef SearchPath, 00277 StringRef RelativePath, 00278 const Module *Imported) { 00279 if (!File) { 00280 if (AddMissingHeaderDeps) 00281 AddFilename(FileName); 00282 else 00283 SeenMissingHeader = true; 00284 } 00285 } 00286 00287 void DFGImpl::AddFilename(StringRef Filename) { 00288 if (FilesSet.insert(Filename)) 00289 Files.push_back(Filename); 00290 } 00291 00292 /// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or 00293 /// other scary characters. 00294 static void PrintFilename(raw_ostream &OS, StringRef Filename) { 00295 for (unsigned i = 0, e = Filename.size(); i != e; ++i) { 00296 if (Filename[i] == ' ' || Filename[i] == '#') 00297 OS << '\\'; 00298 else if (Filename[i] == '$') // $ is escaped by $$. 00299 OS << '$'; 00300 OS << Filename[i]; 00301 } 00302 } 00303 00304 void DFGImpl::OutputDependencyFile() { 00305 if (SeenMissingHeader) { 00306 llvm::sys::fs::remove(OutputFile); 00307 return; 00308 } 00309 00310 std::error_code EC; 00311 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text); 00312 if (EC) { 00313 PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile 00314 << EC.message(); 00315 return; 00316 } 00317 00318 // Write out the dependency targets, trying to avoid overly long 00319 // lines when possible. We try our best to emit exactly the same 00320 // dependency file as GCC (4.2), assuming the included files are the 00321 // same. 00322 const unsigned MaxColumns = 75; 00323 unsigned Columns = 0; 00324 00325 for (std::vector<std::string>::iterator 00326 I = Targets.begin(), E = Targets.end(); I != E; ++I) { 00327 unsigned N = I->length(); 00328 if (Columns == 0) { 00329 Columns += N; 00330 } else if (Columns + N + 2 > MaxColumns) { 00331 Columns = N + 2; 00332 OS << " \\\n "; 00333 } else { 00334 Columns += N + 1; 00335 OS << ' '; 00336 } 00337 // Targets already quoted as needed. 00338 OS << *I; 00339 } 00340 00341 OS << ':'; 00342 Columns += 1; 00343 00344 // Now add each dependency in the order it was seen, but avoiding 00345 // duplicates. 00346 for (std::vector<std::string>::iterator I = Files.begin(), 00347 E = Files.end(); I != E; ++I) { 00348 // Start a new line if this would exceed the column limit. Make 00349 // sure to leave space for a trailing " \" in case we need to 00350 // break the line on the next iteration. 00351 unsigned N = I->length(); 00352 if (Columns + (N + 1) + 2 > MaxColumns) { 00353 OS << " \\\n "; 00354 Columns = 2; 00355 } 00356 OS << ' '; 00357 PrintFilename(OS, *I); 00358 Columns += N + 1; 00359 } 00360 OS << '\n'; 00361 00362 // Create phony targets if requested. 00363 if (PhonyTarget && !Files.empty()) { 00364 // Skip the first entry, this is always the input file itself. 00365 for (std::vector<std::string>::iterator I = Files.begin() + 1, 00366 E = Files.end(); I != E; ++I) { 00367 OS << '\n'; 00368 PrintFilename(OS, *I); 00369 OS << ":\n"; 00370 } 00371 } 00372 } 00373 00374 bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename, 00375 bool IsSystem, bool IsOverridden) { 00376 assert(!IsSystem || needsSystemInputFileVisitation()); 00377 if (IsOverridden) 00378 return true; 00379 00380 Parent.AddFilename(Filename); 00381 return true; 00382 } 00383 00384 void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename) { 00385 if (Parent.includeModuleFiles()) 00386 Parent.AddFilename(Filename); 00387 }