blob: 518f167305728bfe5966c5b9b5ab219574926592 [file] [log] [blame]
Daniel Dunbar750c3582008-10-24 22:12:41 +00001//===--- 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.h"
15#include "clang/Basic/SourceManager.h"
Chris Lattnerb9c3f962009-01-27 07:57:44 +000016#include "clang/Basic/FileManager.h"
Daniel Dunbar750c3582008-10-24 22:12:41 +000017#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"
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +000025#include "llvm/Support/raw_ostream.h"
Daniel Dunbar750c3582008-10-24 22:12:41 +000026#include <string>
27
28using namespace clang;
29
30namespace {
31class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +000032 std::vector<std::string> Files;
33 llvm::StringSet<> FilesSet;
Daniel Dunbar750c3582008-10-24 22:12:41 +000034 const Preprocessor *PP;
Chris Lattner02fbb252009-01-11 19:28:34 +000035 std::vector<std::string> Targets;
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000036 llvm::raw_ostream *OS;
Daniel Dunbar750c3582008-10-24 22:12:41 +000037
38private:
39 bool FileMatchesDepCriteria(const char *Filename,
Chris Lattner9d728512008-10-27 01:19:25 +000040 SrcMgr::CharacteristicKind FileType);
Daniel Dunbar750c3582008-10-24 22:12:41 +000041 void OutputDependencyFile();
42
43public:
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000044 DependencyFileCallback(const Preprocessor *_PP,
45 llvm::raw_ostream *_OS,
46 const std::vector<std::string> &_Targets)
47 : PP(_PP), Targets(_Targets), OS(_OS) {
48 }
49
50 ~DependencyFileCallback() {
51 OutputDependencyFile();
52 OS->flush();
53 delete OS;
54 }
55
Daniel Dunbar750c3582008-10-24 22:12:41 +000056 virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
Chris Lattner9d728512008-10-27 01:19:25 +000057 SrcMgr::CharacteristicKind FileType);
Daniel Dunbar750c3582008-10-24 22:12:41 +000058};
59}
60
Daniel Dunbar750c3582008-10-24 22:12:41 +000061//===----------------------------------------------------------------------===//
62// Dependency file options
63//===----------------------------------------------------------------------===//
Daniel Dunbar750c3582008-10-24 22:12:41 +000064static llvm::cl::opt<std::string>
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000065DependencyFile("dependency-file",
66 llvm::cl::desc("Filename (or -) to write dependency output to"));
67
68static llvm::cl::opt<bool>
69DependenciesIncludeSystemHeaders("sys-header-deps",
70 llvm::cl::desc("Include system headers in dependency output"));
Daniel Dunbar750c3582008-10-24 22:12:41 +000071
Chris Lattner02fbb252009-01-11 19:28:34 +000072static llvm::cl::list<std::string>
73DependencyTargets("MT",
Daniel Dunbar750c3582008-10-24 22:12:41 +000074 llvm::cl::desc("Specify target for dependency"));
75
76// FIXME: Implement feature
77static llvm::cl::opt<bool>
78PhonyDependencyTarget("MP",
79 llvm::cl::desc("Create phony target for each dependency "
80 "(other than main file)"));
81
82bool clang::CreateDependencyFileGen(Preprocessor *PP,
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000083 std::string &ErrStr) {
84 ErrStr = "";
85 if (DependencyFile.empty())
86 return false;
Daniel Dunbar750c3582008-10-24 22:12:41 +000087
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000088 if (DependencyTargets.empty()) {
89 ErrStr = "-dependency-file requires at least one -MT option\n";
Daniel Dunbar750c3582008-10-24 22:12:41 +000090 return false;
91 }
Daniel Dunbar750c3582008-10-24 22:12:41 +000092
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000093 std::string ErrMsg;
94 llvm::raw_ostream *OS =
95 new llvm::raw_fd_ostream(DependencyFile.c_str(), false, ErrStr);
96 if (!ErrMsg.empty()) {
97 ErrStr = "unable to open dependency file: " + ErrMsg;
98 return false;
Daniel Dunbar750c3582008-10-24 22:12:41 +000099 }
100
101 DependencyFileCallback *PPDep =
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000102 new DependencyFileCallback(PP, OS, DependencyTargets);
103 PP->setPPCallbacks(PPDep);
104 return true;
Daniel Dunbar750c3582008-10-24 22:12:41 +0000105}
106
107/// FileMatchesDepCriteria - Determine whether the given Filename should be
108/// considered as a dependency.
109bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
Chris Lattner9d728512008-10-27 01:19:25 +0000110 SrcMgr::CharacteristicKind FileType) {
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000111 if (strcmp("<built-in>", Filename) == 0)
112 return false;
Daniel Dunbar750c3582008-10-24 22:12:41 +0000113
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000114 if (DependenciesIncludeSystemHeaders)
115 return true;
116
117 return FileType == SrcMgr::C_User;
Daniel Dunbar750c3582008-10-24 22:12:41 +0000118}
119
120void DependencyFileCallback::FileChanged(SourceLocation Loc,
121 FileChangeReason Reason,
Chris Lattner9d728512008-10-27 01:19:25 +0000122 SrcMgr::CharacteristicKind FileType) {
Daniel Dunbar750c3582008-10-24 22:12:41 +0000123 if (Reason != PPCallbacks::EnterFile)
124 return;
Chris Lattnerb9c3f962009-01-27 07:57:44 +0000125
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000126 // Dependency generation really does want to go all the way to the
127 // file entry for a source location to find out what is depended on.
128 // We do not want #line markers to affect dependency generation!
Chris Lattnerb9c3f962009-01-27 07:57:44 +0000129 SourceManager &SM = PP->getSourceManager();
130
Chris Lattnere86e4cd02009-01-28 05:42:38 +0000131 const FileEntry *FE =
132 SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
133 if (FE == 0) return;
134
135 const char *Filename = FE->getName();
Daniel Dunbar750c3582008-10-24 22:12:41 +0000136 if (!FileMatchesDepCriteria(Filename, FileType))
137 return;
138
139 // Remove leading "./"
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000140 if (Filename[0] == '.' && Filename[1] == '/')
Daniel Dunbar750c3582008-10-24 22:12:41 +0000141 Filename = &Filename[2];
142
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000143 if (FilesSet.insert(Filename))
144 Files.push_back(Filename);
Daniel Dunbar750c3582008-10-24 22:12:41 +0000145}
146
147void DependencyFileCallback::OutputDependencyFile() {
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000148 // Write out the dependency targets, trying to avoid overly long
149 // lines when possible. We try our best to emit exactly the same
150 // dependency file as GCC (4.2), assuming the included files are the
151 // same.
152 const unsigned MaxColumns = 75;
Chris Lattner02fbb252009-01-11 19:28:34 +0000153 unsigned Columns = 0;
154
155 for (std::vector<std::string>::iterator
156 I = Targets.begin(), E = Targets.end(); I != E; ++I) {
157 unsigned N = I->length();
158 if (Columns == 0) {
159 Columns += N;
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000160 *OS << *I;
Chris Lattner02fbb252009-01-11 19:28:34 +0000161 } else if (Columns + N + 2 > MaxColumns) {
162 Columns = N + 2;
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000163 *OS << " \\\n " << *I;
Chris Lattner02fbb252009-01-11 19:28:34 +0000164 } else {
165 Columns += N + 1;
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000166 *OS << ' ' << *I;
Chris Lattner02fbb252009-01-11 19:28:34 +0000167 }
168 }
169
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000170 *OS << ':';
Chris Lattner02fbb252009-01-11 19:28:34 +0000171 Columns += 1;
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000172
173 // Now add each dependency in the order it was seen, but avoiding
174 // duplicates.
175 for (std::vector<std::string>::iterator I = Files.begin(),
176 E = Files.end(); I != E; ++I) {
177 // Start a new line if this would exceed the column limit. Make
178 // sure to leave space for a trailing " \" in case we need to
179 // break the line on the next iteration.
180 unsigned N = I->length();
181 if (Columns + (N + 1) + 2 > MaxColumns) {
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000182 *OS << " \\\n ";
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000183 Columns = 2;
184 }
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000185 *OS << ' ' << *I;
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000186 Columns += N + 1;
Daniel Dunbar750c3582008-10-24 22:12:41 +0000187 }
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000188 *OS << '\n';
Daniel Dunbar750c3582008-10-24 22:12:41 +0000189
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000190 // Create phony targets if requested.
191 if (PhonyDependencyTarget) {
192 // Skip the first entry, this is always the input file itself.
193 for (std::vector<std::string>::iterator I = Files.begin() + 1,
194 E = Files.end(); I != E; ++I) {
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000195 *OS << '\n';
196 *OS << *I << ":\n";
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000197 }
198 }
Daniel Dunbar750c3582008-10-24 22:12:41 +0000199}
200