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