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