blob: 673ca0734a187dc96fda7d21b68ad723882d9364 [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 <fstream>
27#include <string>
28
29using namespace clang;
30
31namespace {
32class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +000033 std::vector<std::string> Files;
34 llvm::StringSet<> FilesSet;
Daniel Dunbar750c3582008-10-24 22:12:41 +000035 const Preprocessor *PP;
36 std::ofstream OS;
37 const std::string &InputFile;
Chris Lattner02fbb252009-01-11 19:28:34 +000038 std::vector<std::string> Targets;
Daniel Dunbar750c3582008-10-24 22:12:41 +000039
40private:
41 bool FileMatchesDepCriteria(const char *Filename,
Chris Lattner9d728512008-10-27 01:19:25 +000042 SrcMgr::CharacteristicKind FileType);
Daniel Dunbar750c3582008-10-24 22:12:41 +000043 void OutputDependencyFile();
44
45public:
46 DependencyFileCallback(const Preprocessor *PP,
47 const std::string &InputFile,
48 const std::string &DepFile,
Chris Lattner02fbb252009-01-11 19:28:34 +000049 const std::vector<std::string> &Targets,
Daniel Dunbar750c3582008-10-24 22:12:41 +000050 const char *&ErrStr);
51 ~DependencyFileCallback();
52 virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
Chris Lattner9d728512008-10-27 01:19:25 +000053 SrcMgr::CharacteristicKind FileType);
Daniel Dunbar750c3582008-10-24 22:12:41 +000054};
55}
56
57static const char *DependencyFileExt = "d";
58static const char *ObjectFileExt = "o";
59
60//===----------------------------------------------------------------------===//
61// Dependency file options
62//===----------------------------------------------------------------------===//
63static llvm::cl::opt<bool>
64GenerateDependencyFile("MD",
65 llvm::cl::desc("Generate dependency for main source file "
66 "(system headers included)"));
67
68static llvm::cl::opt<bool>
69GenerateDependencyFileNoSysHeaders("MMD",
70 llvm::cl::desc("Generate dependency for main source file "
71 "(no system headers)"));
72
73static llvm::cl::opt<std::string>
74DependencyOutputFile("MF",
75 llvm::cl::desc("Specify dependency output file"));
76
Chris Lattner02fbb252009-01-11 19:28:34 +000077static llvm::cl::list<std::string>
78DependencyTargets("MT",
Daniel Dunbar750c3582008-10-24 22:12:41 +000079 llvm::cl::desc("Specify target for dependency"));
80
81// FIXME: Implement feature
82static llvm::cl::opt<bool>
83PhonyDependencyTarget("MP",
84 llvm::cl::desc("Create phony target for each dependency "
85 "(other than main file)"));
86
87bool clang::CreateDependencyFileGen(Preprocessor *PP,
88 std::string &OutputFile,
89 const std::string &InputFile,
90 const char *&ErrStr) {
91 assert(!InputFile.empty() && "No file given");
92
93 ErrStr = NULL;
94
95 if (!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) {
Chris Lattner02fbb252009-01-11 19:28:34 +000096 if (!DependencyOutputFile.empty() || !DependencyTargets.empty() ||
Daniel Dunbar750c3582008-10-24 22:12:41 +000097 PhonyDependencyTarget)
98 ErrStr = "Error: to generate dependencies you must specify -MD or -MMD\n";
99 return false;
100 }
101
102 // Handle conflicting options
103 if (GenerateDependencyFileNoSysHeaders)
104 GenerateDependencyFile = false;
105
106 // Determine name of dependency output filename
107 llvm::sys::Path DepFile;
108 if (!DependencyOutputFile.empty())
109 DepFile = DependencyOutputFile;
110 else if (!OutputFile.empty()) {
111 DepFile = OutputFile;
112 DepFile.eraseSuffix();
113 DepFile.appendSuffix(DependencyFileExt);
114 }
115 else {
116 DepFile = InputFile;
117 DepFile.eraseSuffix();
118 DepFile.appendSuffix(DependencyFileExt);
119 }
120
Chris Lattner02fbb252009-01-11 19:28:34 +0000121 std::vector<std::string> Targets(DependencyTargets);
122
123 // Infer target name if unspecified
124 if (Targets.empty()) {
125 if (!OutputFile.empty()) {
126 llvm::sys::Path TargetPath(OutputFile);
127 TargetPath.eraseSuffix();
128 TargetPath.appendSuffix(ObjectFileExt);
129 Targets.push_back(TargetPath.toString());
130 } else {
131 llvm::sys::Path TargetPath(InputFile);
132 TargetPath.eraseSuffix();
133 TargetPath.appendSuffix(ObjectFileExt);
134 Targets.push_back(TargetPath.toString());
135 }
Daniel Dunbar750c3582008-10-24 22:12:41 +0000136 }
137
138 DependencyFileCallback *PPDep =
139 new DependencyFileCallback(PP, InputFile, DepFile.toString(),
Chris Lattner02fbb252009-01-11 19:28:34 +0000140 Targets, ErrStr);
Daniel Dunbar750c3582008-10-24 22:12:41 +0000141 if (ErrStr){
142 delete PPDep;
143 return false;
144 }
145 else {
146 PP->setPPCallbacks(PPDep);
147 return true;
148 }
149}
150
151/// FileMatchesDepCriteria - Determine whether the given Filename should be
152/// considered as a dependency.
153bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
Chris Lattner9d728512008-10-27 01:19:25 +0000154 SrcMgr::CharacteristicKind FileType) {
Daniel Dunbar750c3582008-10-24 22:12:41 +0000155 if (strcmp(InputFile.c_str(), Filename) != 0 &&
156 strcmp("<predefines>", Filename) != 0) {
157 if (GenerateDependencyFileNoSysHeaders)
158 return FileType == SrcMgr::C_User;
159 else
160 return true;
161 }
162
163 return false;
164}
165
166void DependencyFileCallback::FileChanged(SourceLocation Loc,
167 FileChangeReason Reason,
Chris Lattner9d728512008-10-27 01:19:25 +0000168 SrcMgr::CharacteristicKind FileType) {
Daniel Dunbar750c3582008-10-24 22:12:41 +0000169 if (Reason != PPCallbacks::EnterFile)
170 return;
Chris Lattnerb9c3f962009-01-27 07:57:44 +0000171
172 // Depedency generation really does want to go all the way to the file entry
173 // for a source location to find out what is depended on. We do not want
174 // #line markers to affect dependency generation!
175 SourceManager &SM = PP->getSourceManager();
176
Chris Lattnere86e4cd02009-01-28 05:42:38 +0000177 const FileEntry *FE =
178 SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
179 if (FE == 0) return;
180
181 const char *Filename = FE->getName();
Daniel Dunbar750c3582008-10-24 22:12:41 +0000182 if (!FileMatchesDepCriteria(Filename, FileType))
183 return;
184
185 // Remove leading "./"
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000186 if (Filename[0] == '.' && Filename[1] == '/')
Daniel Dunbar750c3582008-10-24 22:12:41 +0000187 Filename = &Filename[2];
188
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000189 if (FilesSet.insert(Filename))
190 Files.push_back(Filename);
Daniel Dunbar750c3582008-10-24 22:12:41 +0000191}
192
193void DependencyFileCallback::OutputDependencyFile() {
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000194 // Write out the dependency targets, trying to avoid overly long
195 // lines when possible. We try our best to emit exactly the same
196 // dependency file as GCC (4.2), assuming the included files are the
197 // same.
198 const unsigned MaxColumns = 75;
Chris Lattner02fbb252009-01-11 19:28:34 +0000199 unsigned Columns = 0;
200
201 for (std::vector<std::string>::iterator
202 I = Targets.begin(), E = Targets.end(); I != E; ++I) {
203 unsigned N = I->length();
204 if (Columns == 0) {
205 Columns += N;
206 OS << *I;
207 } else if (Columns + N + 2 > MaxColumns) {
208 Columns = N + 2;
209 OS << " \\\n " << *I;
210 } else {
211 Columns += N + 1;
212 OS << " " << *I;
213 }
214 }
215
216 OS << ":";
217 Columns += 1;
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000218
219 // Now add each dependency in the order it was seen, but avoiding
220 // duplicates.
221 for (std::vector<std::string>::iterator I = Files.begin(),
222 E = Files.end(); I != E; ++I) {
223 // Start a new line if this would exceed the column limit. Make
224 // sure to leave space for a trailing " \" in case we need to
225 // break the line on the next iteration.
226 unsigned N = I->length();
227 if (Columns + (N + 1) + 2 > MaxColumns) {
228 OS << " \\\n ";
229 Columns = 2;
230 }
231 OS << " " << *I;
232 Columns += N + 1;
Daniel Dunbar750c3582008-10-24 22:12:41 +0000233 }
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000234 OS << "\n";
Daniel Dunbar750c3582008-10-24 22:12:41 +0000235
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000236 // Create phony targets if requested.
237 if (PhonyDependencyTarget) {
238 // Skip the first entry, this is always the input file itself.
239 for (std::vector<std::string>::iterator I = Files.begin() + 1,
240 E = Files.end(); I != E; ++I) {
241 OS << "\n";
242 OS << *I << ":\n";
243 }
244 }
Daniel Dunbar750c3582008-10-24 22:12:41 +0000245}
246
247DependencyFileCallback::DependencyFileCallback(const Preprocessor *PP,
248 const std::string &InputFile,
249 const std::string &DepFile,
Chris Lattner02fbb252009-01-11 19:28:34 +0000250 const std::vector<std::string>
251 &Targets,
Daniel Dunbar750c3582008-10-24 22:12:41 +0000252 const char *&ErrStr)
Chris Lattner02fbb252009-01-11 19:28:34 +0000253 : PP(PP), InputFile(InputFile), Targets(Targets) {
Daniel Dunbar750c3582008-10-24 22:12:41 +0000254
255 OS.open(DepFile.c_str());
256 if (OS.fail())
257 ErrStr = "Could not open dependency output file\n";
258 else
259 ErrStr = NULL;
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000260
261 Files.push_back(InputFile);
Daniel Dunbar750c3582008-10-24 22:12:41 +0000262}
263
264DependencyFileCallback::~DependencyFileCallback() {
265 if ((!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) ||
266 OS.fail())
267 return;
268
269 OutputDependencyFile();
270 OS.close();
271}
272