blob: 9ef209eeebbb8050b489731eb39f9dab3b2e30df [file] [log] [blame]
Daniel Dunbar35fe5de2008-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
Ted Kremenek377a3192009-03-31 18:58:14 +000014#include "clang-cc.h"
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000015#include "clang/Basic/SourceManager.h"
Chris Lattner836774b2009-01-27 07:57:44 +000016#include "clang/Basic/FileManager.h"
Daniel Dunbar35fe5de2008-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 Dunbar4cdc4a52008-10-27 20:01:06 +000025#include "llvm/Support/raw_ostream.h"
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000026#include <string>
27
28using namespace clang;
29
30namespace {
31class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
Daniel Dunbar4cdc4a52008-10-27 20:01:06 +000032 std::vector<std::string> Files;
33 llvm::StringSet<> FilesSet;
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000034 const Preprocessor *PP;
Chris Lattner6b0d6e22009-01-11 19:28:34 +000035 std::vector<std::string> Targets;
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +000036 llvm::raw_ostream *OS;
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000037
Daniel Dunbarebfb1bc2009-05-03 09:35:25 +000038 // FIXME: This functionality should be moved into a common class for
39 // chaining callbacks.
40 PPCallbacks *PrevCallbacks;
41
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000042private:
43 bool FileMatchesDepCriteria(const char *Filename,
Chris Lattner7a4864e2008-10-27 01:19:25 +000044 SrcMgr::CharacteristicKind FileType);
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000045 void OutputDependencyFile();
46
47public:
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +000048 DependencyFileCallback(const Preprocessor *_PP,
49 llvm::raw_ostream *_OS,
Daniel Dunbarebfb1bc2009-05-03 09:35:25 +000050 const std::vector<std::string> &_Targets,
51 PPCallbacks *_PrevCallbacks)
52 : PP(_PP), Targets(_Targets), OS(_OS), PrevCallbacks(_PrevCallbacks) {
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +000053 }
54
55 ~DependencyFileCallback() {
Daniel Dunbarebfb1bc2009-05-03 09:35:25 +000056 if (PrevCallbacks)
57 delete PrevCallbacks;
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +000058 OutputDependencyFile();
59 OS->flush();
60 delete OS;
61 }
62
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000063 virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
Chris Lattner7a4864e2008-10-27 01:19:25 +000064 SrcMgr::CharacteristicKind FileType);
Daniel Dunbarebfb1bc2009-05-03 09:35:25 +000065
66 virtual void Ident(SourceLocation Loc, const std::string &str) {
67 if (PrevCallbacks)
68 PrevCallbacks->Ident(Loc, str);
69 }
70
71 virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
72 const std::string &Str) {
73 if (PrevCallbacks)
74 PrevCallbacks->PragmaComment(Loc, Kind, Str);
75 }
76
77 virtual void MacroExpands(const Token &Id, const MacroInfo* MI) {
78 if (PrevCallbacks)
79 PrevCallbacks->MacroExpands(Id, MI);
80 }
81
82 virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI) {
83 if (PrevCallbacks)
84 PrevCallbacks->MacroDefined(II, MI);
85 }
86
87 virtual void MacroUndefined(const IdentifierInfo *II, const MacroInfo *MI) {
88 if (PrevCallbacks)
89 PrevCallbacks->MacroUndefined(II, MI);
90 }
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000091};
92}
93
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000094//===----------------------------------------------------------------------===//
95// Dependency file options
96//===----------------------------------------------------------------------===//
Daniel Dunbar35fe5de2008-10-24 22:12:41 +000097static llvm::cl::opt<std::string>
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +000098DependencyFile("dependency-file",
99 llvm::cl::desc("Filename (or -) to write dependency output to"));
100
101static llvm::cl::opt<bool>
102DependenciesIncludeSystemHeaders("sys-header-deps",
103 llvm::cl::desc("Include system headers in dependency output"));
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000104
Chris Lattner6b0d6e22009-01-11 19:28:34 +0000105static llvm::cl::list<std::string>
106DependencyTargets("MT",
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000107 llvm::cl::desc("Specify target for dependency"));
108
109// FIXME: Implement feature
110static llvm::cl::opt<bool>
111PhonyDependencyTarget("MP",
112 llvm::cl::desc("Create phony target for each dependency "
113 "(other than main file)"));
114
115bool clang::CreateDependencyFileGen(Preprocessor *PP,
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000116 std::string &ErrStr) {
117 ErrStr = "";
118 if (DependencyFile.empty())
119 return false;
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000120
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000121 if (DependencyTargets.empty()) {
122 ErrStr = "-dependency-file requires at least one -MT option\n";
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000123 return false;
124 }
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000125
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000126 std::string ErrMsg;
Daniel Dunbar049b7242009-03-30 06:36:42 +0000127 llvm::raw_ostream *OS;
128 if (DependencyFile == "-") {
129 OS = new llvm::raw_stdout_ostream();
130 } else {
131 OS = new llvm::raw_fd_ostream(DependencyFile.c_str(), false, ErrStr);
132 if (!ErrMsg.empty()) {
133 ErrStr = "unable to open dependency file: " + ErrMsg;
134 return false;
135 }
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000136 }
137
Daniel Dunbarebfb1bc2009-05-03 09:35:25 +0000138 // Claim any previous callbacks.
139 PPCallbacks *Prev = PP->getPPCallbacks();
140 if (Prev)
141 PP->setPPCallbacks(0);
142
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000143 DependencyFileCallback *PPDep =
Daniel Dunbarebfb1bc2009-05-03 09:35:25 +0000144 new DependencyFileCallback(PP, OS, DependencyTargets, Prev);
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000145 PP->setPPCallbacks(PPDep);
146 return true;
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000147}
148
149/// FileMatchesDepCriteria - Determine whether the given Filename should be
150/// considered as a dependency.
151bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
Chris Lattner7a4864e2008-10-27 01:19:25 +0000152 SrcMgr::CharacteristicKind FileType) {
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000153 if (strcmp("<built-in>", Filename) == 0)
154 return false;
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000155
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000156 if (DependenciesIncludeSystemHeaders)
157 return true;
158
159 return FileType == SrcMgr::C_User;
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000160}
161
162void DependencyFileCallback::FileChanged(SourceLocation Loc,
163 FileChangeReason Reason,
Chris Lattner7a4864e2008-10-27 01:19:25 +0000164 SrcMgr::CharacteristicKind FileType) {
Daniel Dunbarebfb1bc2009-05-03 09:35:25 +0000165 if (PrevCallbacks)
166 PrevCallbacks->FileChanged(Loc, Reason, FileType);
167
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000168 if (Reason != PPCallbacks::EnterFile)
169 return;
Chris Lattner836774b2009-01-27 07:57:44 +0000170
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000171 // Dependency generation really does want to go all the way to the
172 // file entry for a source location to find out what is depended on.
173 // We do not want #line markers to affect dependency generation!
Chris Lattner836774b2009-01-27 07:57:44 +0000174 SourceManager &SM = PP->getSourceManager();
175
Chris Lattnere88c1952009-01-28 05:42:38 +0000176 const FileEntry *FE =
177 SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
178 if (FE == 0) return;
179
180 const char *Filename = FE->getName();
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000181 if (!FileMatchesDepCriteria(Filename, FileType))
182 return;
183
184 // Remove leading "./"
Daniel Dunbar4cdc4a52008-10-27 20:01:06 +0000185 if (Filename[0] == '.' && Filename[1] == '/')
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000186 Filename = &Filename[2];
187
Daniel Dunbar4cdc4a52008-10-27 20:01:06 +0000188 if (FilesSet.insert(Filename))
189 Files.push_back(Filename);
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000190}
191
192void DependencyFileCallback::OutputDependencyFile() {
Daniel Dunbar4cdc4a52008-10-27 20:01:06 +0000193 // Write out the dependency targets, trying to avoid overly long
194 // lines when possible. We try our best to emit exactly the same
195 // dependency file as GCC (4.2), assuming the included files are the
196 // same.
197 const unsigned MaxColumns = 75;
Chris Lattner6b0d6e22009-01-11 19:28:34 +0000198 unsigned Columns = 0;
199
200 for (std::vector<std::string>::iterator
201 I = Targets.begin(), E = Targets.end(); I != E; ++I) {
202 unsigned N = I->length();
203 if (Columns == 0) {
204 Columns += N;
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000205 *OS << *I;
Chris Lattner6b0d6e22009-01-11 19:28:34 +0000206 } else if (Columns + N + 2 > MaxColumns) {
207 Columns = N + 2;
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000208 *OS << " \\\n " << *I;
Chris Lattner6b0d6e22009-01-11 19:28:34 +0000209 } else {
210 Columns += N + 1;
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000211 *OS << ' ' << *I;
Chris Lattner6b0d6e22009-01-11 19:28:34 +0000212 }
213 }
214
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000215 *OS << ':';
Chris Lattner6b0d6e22009-01-11 19:28:34 +0000216 Columns += 1;
Daniel Dunbar4cdc4a52008-10-27 20:01:06 +0000217
218 // Now add each dependency in the order it was seen, but avoiding
219 // duplicates.
220 for (std::vector<std::string>::iterator I = Files.begin(),
221 E = Files.end(); I != E; ++I) {
222 // Start a new line if this would exceed the column limit. Make
223 // sure to leave space for a trailing " \" in case we need to
224 // break the line on the next iteration.
225 unsigned N = I->length();
226 if (Columns + (N + 1) + 2 > MaxColumns) {
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000227 *OS << " \\\n ";
Daniel Dunbar4cdc4a52008-10-27 20:01:06 +0000228 Columns = 2;
229 }
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000230 *OS << ' ' << *I;
Daniel Dunbar4cdc4a52008-10-27 20:01:06 +0000231 Columns += N + 1;
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000232 }
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000233 *OS << '\n';
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000234
Daniel Dunbar4cdc4a52008-10-27 20:01:06 +0000235 // Create phony targets if requested.
236 if (PhonyDependencyTarget) {
237 // Skip the first entry, this is always the input file itself.
238 for (std::vector<std::string>::iterator I = Files.begin() + 1,
239 E = Files.end(); I != E; ++I) {
Daniel Dunbar0bf13eb2009-03-30 00:34:04 +0000240 *OS << '\n';
241 *OS << *I << ":\n";
Daniel Dunbar4cdc4a52008-10-27 20:01:06 +0000242 }
243 }
Daniel Dunbar35fe5de2008-10-24 22:12:41 +0000244}
245