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 "llvm/ADT/StringSet.h" 00024 #include "llvm/Support/Path.h" 00025 #include "llvm/Support/raw_ostream.h" 00026 00027 using namespace clang; 00028 00029 namespace { 00030 class DependencyFileCallback : public PPCallbacks { 00031 std::vector<std::string> Files; 00032 llvm::StringSet<> FilesSet; 00033 const Preprocessor *PP; 00034 std::string OutputFile; 00035 std::vector<std::string> Targets; 00036 bool IncludeSystemHeaders; 00037 bool PhonyTarget; 00038 bool AddMissingHeaderDeps; 00039 bool SeenMissingHeader; 00040 private: 00041 bool FileMatchesDepCriteria(const char *Filename, 00042 SrcMgr::CharacteristicKind FileType); 00043 void AddFilename(StringRef Filename); 00044 void OutputDependencyFile(); 00045 00046 public: 00047 DependencyFileCallback(const Preprocessor *_PP, 00048 const DependencyOutputOptions &Opts) 00049 : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets), 00050 IncludeSystemHeaders(Opts.IncludeSystemHeaders), 00051 PhonyTarget(Opts.UsePhonyTargets), 00052 AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), 00053 SeenMissingHeader(false) {} 00054 00055 virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, 00056 SrcMgr::CharacteristicKind FileType, 00057 FileID PrevFID); 00058 virtual void InclusionDirective(SourceLocation HashLoc, 00059 const Token &IncludeTok, 00060 StringRef FileName, 00061 bool IsAngled, 00062 const FileEntry *File, 00063 SourceLocation EndLoc, 00064 StringRef SearchPath, 00065 StringRef RelativePath); 00066 00067 virtual void EndOfMainFile() { 00068 OutputDependencyFile(); 00069 } 00070 }; 00071 } 00072 00073 void clang::AttachDependencyFileGen(Preprocessor &PP, 00074 const DependencyOutputOptions &Opts) { 00075 if (Opts.Targets.empty()) { 00076 PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT); 00077 return; 00078 } 00079 00080 // Disable the "file not found" diagnostic if the -MG option was given. 00081 if (Opts.AddMissingHeaderDeps) 00082 PP.SetSuppressIncludeNotFoundError(true); 00083 00084 PP.addPPCallbacks(new DependencyFileCallback(&PP, Opts)); 00085 } 00086 00087 /// FileMatchesDepCriteria - Determine whether the given Filename should be 00088 /// considered as a dependency. 00089 bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename, 00090 SrcMgr::CharacteristicKind FileType) { 00091 if (strcmp("<built-in>", Filename) == 0) 00092 return false; 00093 00094 if (IncludeSystemHeaders) 00095 return true; 00096 00097 return FileType == SrcMgr::C_User; 00098 } 00099 00100 void DependencyFileCallback::FileChanged(SourceLocation Loc, 00101 FileChangeReason Reason, 00102 SrcMgr::CharacteristicKind FileType, 00103 FileID PrevFID) { 00104 if (Reason != PPCallbacks::EnterFile) 00105 return; 00106 00107 // Dependency generation really does want to go all the way to the 00108 // file entry for a source location to find out what is depended on. 00109 // We do not want #line markers to affect dependency generation! 00110 SourceManager &SM = PP->getSourceManager(); 00111 00112 const FileEntry *FE = 00113 SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc))); 00114 if (FE == 0) return; 00115 00116 StringRef Filename = FE->getName(); 00117 if (!FileMatchesDepCriteria(Filename.data(), FileType)) 00118 return; 00119 00120 // Remove leading "./" (or ".//" or "././" etc.) 00121 while (Filename.size() > 2 && Filename[0] == '.' && 00122 llvm::sys::path::is_separator(Filename[1])) { 00123 Filename = Filename.substr(1); 00124 while (llvm::sys::path::is_separator(Filename[0])) 00125 Filename = Filename.substr(1); 00126 } 00127 00128 AddFilename(Filename); 00129 } 00130 00131 void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc, 00132 const Token &IncludeTok, 00133 StringRef FileName, 00134 bool IsAngled, 00135 const FileEntry *File, 00136 SourceLocation EndLoc, 00137 StringRef SearchPath, 00138 StringRef RelativePath) { 00139 if (!File) { 00140 if (AddMissingHeaderDeps) 00141 AddFilename(FileName); 00142 else 00143 SeenMissingHeader = true; 00144 } 00145 } 00146 00147 void DependencyFileCallback::AddFilename(StringRef Filename) { 00148 if (FilesSet.insert(Filename)) 00149 Files.push_back(Filename); 00150 } 00151 00152 /// PrintFilename - GCC escapes spaces, but apparently not ' or " or other 00153 /// scary characters. 00154 static void PrintFilename(raw_ostream &OS, StringRef Filename) { 00155 for (unsigned i = 0, e = Filename.size(); i != e; ++i) { 00156 if (Filename[i] == ' ') 00157 OS << '\\'; 00158 OS << Filename[i]; 00159 } 00160 } 00161 00162 void DependencyFileCallback::OutputDependencyFile() { 00163 if (SeenMissingHeader) { 00164 llvm::sys::Path(OutputFile).eraseFromDisk(); 00165 return; 00166 } 00167 00168 std::string Err; 00169 llvm::raw_fd_ostream OS(OutputFile.c_str(), Err); 00170 if (!Err.empty()) { 00171 PP->getDiagnostics().Report(diag::err_fe_error_opening) 00172 << OutputFile << Err; 00173 return; 00174 } 00175 00176 // Write out the dependency targets, trying to avoid overly long 00177 // lines when possible. We try our best to emit exactly the same 00178 // dependency file as GCC (4.2), assuming the included files are the 00179 // same. 00180 const unsigned MaxColumns = 75; 00181 unsigned Columns = 0; 00182 00183 for (std::vector<std::string>::iterator 00184 I = Targets.begin(), E = Targets.end(); I != E; ++I) { 00185 unsigned N = I->length(); 00186 if (Columns == 0) { 00187 Columns += N; 00188 } else if (Columns + N + 2 > MaxColumns) { 00189 Columns = N + 2; 00190 OS << " \\\n "; 00191 } else { 00192 Columns += N + 1; 00193 OS << ' '; 00194 } 00195 // Targets already quoted as needed. 00196 OS << *I; 00197 } 00198 00199 OS << ':'; 00200 Columns += 1; 00201 00202 // Now add each dependency in the order it was seen, but avoiding 00203 // duplicates. 00204 for (std::vector<std::string>::iterator I = Files.begin(), 00205 E = Files.end(); I != E; ++I) { 00206 // Start a new line if this would exceed the column limit. Make 00207 // sure to leave space for a trailing " \" in case we need to 00208 // break the line on the next iteration. 00209 unsigned N = I->length(); 00210 if (Columns + (N + 1) + 2 > MaxColumns) { 00211 OS << " \\\n "; 00212 Columns = 2; 00213 } 00214 OS << ' '; 00215 PrintFilename(OS, *I); 00216 Columns += N + 1; 00217 } 00218 OS << '\n'; 00219 00220 // Create phony targets if requested. 00221 if (PhonyTarget && !Files.empty()) { 00222 // Skip the first entry, this is always the input file itself. 00223 for (std::vector<std::string>::iterator I = Files.begin() + 1, 00224 E = Files.end(); I != E; ++I) { 00225 OS << '\n'; 00226 PrintFilename(OS, *I); 00227 OS << ":\n"; 00228 } 00229 } 00230 } 00231