DependencyFile.cpp revision dbd8209b33e6c9f151e4913a9c095d64a95439c4
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/SourceLocation.h" 17#include "clang/Basic/SourceManager.h" 18#include "clang/Frontend/DependencyOutputOptions.h" 19#include "clang/Frontend/FrontendDiagnostic.h" 20#include "clang/Lex/DirectoryLookup.h" 21#include "clang/Lex/PPCallbacks.h" 22#include "clang/Lex/Preprocessor.h" 23#include "llvm/ADT/StringSet.h" 24#include "llvm/Support/raw_ostream.h" 25#include <string> 26 27using namespace clang; 28 29namespace { 30class DependencyFileCallback : public PPCallbacks { 31 std::vector<std::string> Files; 32 llvm::StringSet<> FilesSet; 33 const Preprocessor *PP; 34 std::vector<std::string> Targets; 35 llvm::raw_ostream *OS; 36 bool IncludeSystemHeaders; 37 bool PhonyTarget; 38private: 39 bool FileMatchesDepCriteria(const char *Filename, 40 SrcMgr::CharacteristicKind FileType); 41 void OutputDependencyFile(); 42 43public: 44 DependencyFileCallback(const Preprocessor *_PP, 45 llvm::raw_ostream *_OS, 46 const DependencyOutputOptions &Opts) 47 : PP(_PP), Targets(Opts.Targets), OS(_OS), 48 IncludeSystemHeaders(Opts.IncludeSystemHeaders), 49 PhonyTarget(Opts.UsePhonyTargets) {} 50 51 virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, 52 SrcMgr::CharacteristicKind FileType); 53 54 virtual void EndOfMainFile() { 55 OutputDependencyFile(); 56 OS->flush(); 57 delete OS; 58 OS = 0; 59 } 60}; 61} 62 63void clang::AttachDependencyFileGen(Preprocessor &PP, 64 const DependencyOutputOptions &Opts) { 65 if (Opts.Targets.empty()) { 66 PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT); 67 return; 68 } 69 70 std::string Err; 71 llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err)); 72 if (!Err.empty()) { 73 PP.getDiagnostics().Report(diag::err_fe_error_opening) 74 << Opts.OutputFile << Err; 75 return; 76 } 77 78 PP.addPPCallbacks(new DependencyFileCallback(&PP, OS, Opts)); 79} 80 81/// FileMatchesDepCriteria - Determine whether the given Filename should be 82/// considered as a dependency. 83bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename, 84 SrcMgr::CharacteristicKind FileType) { 85 if (strcmp("<built-in>", Filename) == 0) 86 return false; 87 88 if (IncludeSystemHeaders) 89 return true; 90 91 return FileType == SrcMgr::C_User; 92} 93 94void DependencyFileCallback::FileChanged(SourceLocation Loc, 95 FileChangeReason Reason, 96 SrcMgr::CharacteristicKind FileType) { 97 if (Reason != PPCallbacks::EnterFile) 98 return; 99 100 // Dependency generation really does want to go all the way to the 101 // file entry for a source location to find out what is depended on. 102 // We do not want #line markers to affect dependency generation! 103 SourceManager &SM = PP->getSourceManager(); 104 105 const FileEntry *FE = 106 SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc))); 107 if (FE == 0) return; 108 109 const char *Filename = FE->getName(); 110 if (!FileMatchesDepCriteria(Filename, FileType)) 111 return; 112 113 // Remove leading "./" 114 if (Filename[0] == '.' && Filename[1] == '/') 115 Filename = &Filename[2]; 116 117 if (FilesSet.insert(Filename)) 118 Files.push_back(Filename); 119} 120 121void DependencyFileCallback::OutputDependencyFile() { 122 // Write out the dependency targets, trying to avoid overly long 123 // lines when possible. We try our best to emit exactly the same 124 // dependency file as GCC (4.2), assuming the included files are the 125 // same. 126 const unsigned MaxColumns = 75; 127 unsigned Columns = 0; 128 129 for (std::vector<std::string>::iterator 130 I = Targets.begin(), E = Targets.end(); I != E; ++I) { 131 unsigned N = I->length(); 132 if (Columns == 0) { 133 Columns += N; 134 *OS << *I; 135 } else if (Columns + N + 2 > MaxColumns) { 136 Columns = N + 2; 137 *OS << " \\\n " << *I; 138 } else { 139 Columns += N + 1; 140 *OS << ' ' << *I; 141 } 142 } 143 144 *OS << ':'; 145 Columns += 1; 146 147 // Now add each dependency in the order it was seen, but avoiding 148 // duplicates. 149 for (std::vector<std::string>::iterator I = Files.begin(), 150 E = Files.end(); I != E; ++I) { 151 // Start a new line if this would exceed the column limit. Make 152 // sure to leave space for a trailing " \" in case we need to 153 // break the line on the next iteration. 154 unsigned N = I->length(); 155 if (Columns + (N + 1) + 2 > MaxColumns) { 156 *OS << " \\\n "; 157 Columns = 2; 158 } 159 *OS << ' ' << *I; 160 Columns += N + 1; 161 } 162 *OS << '\n'; 163 164 // Create phony targets if requested. 165 if (PhonyTarget) { 166 // Skip the first entry, this is always the input file itself. 167 for (std::vector<std::string>::iterator I = Files.begin() + 1, 168 E = Files.end(); I != E; ++I) { 169 *OS << '\n'; 170 *OS << *I << ":\n"; 171 } 172 } 173} 174 175