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