Silence a GCC member initialization order warning.
[clang.git] / Driver / DependencyFile.cpp
blobfc64557e444ac80c627ed0a81e4cedd2b258f559
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.
12 //===----------------------------------------------------------------------===//
14 #include "clang.h"
15 #include "clang/Basic/SourceManager.h"
16 #include "clang/Lex/Preprocessor.h"
17 #include "clang/Lex/PPCallbacks.h"
18 #include "clang/Lex/DirectoryLookup.h"
19 #include "clang/Basic/SourceLocation.h"
20 #include "llvm/ADT/StringSet.h"
21 #include "llvm/System/Path.h"
22 #include "llvm/Support/CommandLine.h"
23 #include "llvm/Support/Compiler.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include <fstream>
26 #include <string>
28 using namespace clang;
30 namespace {
31 class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
32 std::vector<std::string> Files;
33 llvm::StringSet<> FilesSet;
34 const Preprocessor *PP;
35 std::ofstream OS;
36 const std::string &InputFile;
37 std::string Target;
39 private:
40 bool FileMatchesDepCriteria(const char *Filename,
41 SrcMgr::CharacteristicKind FileType);
42 void OutputDependencyFile();
44 public:
45 DependencyFileCallback(const Preprocessor *PP,
46 const std::string &InputFile,
47 const std::string &DepFile,
48 const std::string &Target,
49 const char *&ErrStr);
50 ~DependencyFileCallback();
51 virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
52 SrcMgr::CharacteristicKind FileType);
56 static const char *DependencyFileExt = "d";
57 static const char *ObjectFileExt = "o";
59 //===----------------------------------------------------------------------===//
60 // Dependency file options
61 //===----------------------------------------------------------------------===//
62 static llvm::cl::opt<bool>
63 GenerateDependencyFile("MD",
64 llvm::cl::desc("Generate dependency for main source file "
65 "(system headers included)"));
67 static llvm::cl::opt<bool>
68 GenerateDependencyFileNoSysHeaders("MMD",
69 llvm::cl::desc("Generate dependency for main source file "
70 "(no system headers)"));
72 static llvm::cl::opt<std::string>
73 DependencyOutputFile("MF",
74 llvm::cl::desc("Specify dependency output file"));
76 static llvm::cl::opt<std::string>
77 DependencyTarget("MT",
78 llvm::cl::desc("Specify target for dependency"));
80 // FIXME: Implement feature
81 static llvm::cl::opt<bool>
82 PhonyDependencyTarget("MP",
83 llvm::cl::desc("Create phony target for each dependency "
84 "(other than main file)"));
86 bool clang::CreateDependencyFileGen(Preprocessor *PP,
87 std::string &OutputFile,
88 const std::string &InputFile,
89 const char *&ErrStr) {
90 assert(!InputFile.empty() && "No file given");
92 ErrStr = NULL;
94 if (!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) {
95 if (!DependencyOutputFile.empty() || !DependencyTarget.empty() ||
96 PhonyDependencyTarget)
97 ErrStr = "Error: to generate dependencies you must specify -MD or -MMD\n";
98 return false;
101 // Handle conflicting options
102 if (GenerateDependencyFileNoSysHeaders)
103 GenerateDependencyFile = false;
105 // Determine name of dependency output filename
106 llvm::sys::Path DepFile;
107 if (!DependencyOutputFile.empty())
108 DepFile = DependencyOutputFile;
109 else if (!OutputFile.empty()) {
110 DepFile = OutputFile;
111 DepFile.eraseSuffix();
112 DepFile.appendSuffix(DependencyFileExt);
114 else {
115 DepFile = InputFile;
116 DepFile.eraseSuffix();
117 DepFile.appendSuffix(DependencyFileExt);
120 // Determine name of target
121 std::string Target;
122 if (!DependencyTarget.empty())
123 Target = DependencyTarget;
124 else if (!OutputFile.empty()) {
125 llvm::sys::Path TargetPath(OutputFile);
126 TargetPath.eraseSuffix();
127 TargetPath.appendSuffix(ObjectFileExt);
128 Target = TargetPath.toString();
130 else {
131 llvm::sys::Path TargetPath(InputFile);
132 TargetPath.eraseSuffix();
133 TargetPath.appendSuffix(ObjectFileExt);
134 Target = TargetPath.toString();
137 DependencyFileCallback *PPDep =
138 new DependencyFileCallback(PP, InputFile, DepFile.toString(),
139 Target, ErrStr);
140 if (ErrStr){
141 delete PPDep;
142 return false;
144 else {
145 PP->setPPCallbacks(PPDep);
146 return true;
150 /// FileMatchesDepCriteria - Determine whether the given Filename should be
151 /// considered as a dependency.
152 bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
153 SrcMgr::CharacteristicKind FileType) {
154 if (strcmp(InputFile.c_str(), Filename) != 0 &&
155 strcmp("<predefines>", Filename) != 0) {
156 if (GenerateDependencyFileNoSysHeaders)
157 return FileType == SrcMgr::C_User;
158 else
159 return true;
162 return false;
165 void DependencyFileCallback::FileChanged(SourceLocation Loc,
166 FileChangeReason Reason,
167 SrcMgr::CharacteristicKind FileType) {
168 if (Reason != PPCallbacks::EnterFile)
169 return;
171 const char *Filename = PP->getSourceManager().getSourceName(Loc);
172 if (!FileMatchesDepCriteria(Filename, FileType))
173 return;
175 // Remove leading "./"
176 if (Filename[0] == '.' && Filename[1] == '/')
177 Filename = &Filename[2];
179 if (FilesSet.insert(Filename))
180 Files.push_back(Filename);
183 void DependencyFileCallback::OutputDependencyFile() {
184 // Write out the dependency targets, trying to avoid overly long
185 // lines when possible. We try our best to emit exactly the same
186 // dependency file as GCC (4.2), assuming the included files are the
187 // same.
188 const unsigned MaxColumns = 75;
190 OS << Target << ":";
191 unsigned Columns = Target.length() + 1;
193 // Now add each dependency in the order it was seen, but avoiding
194 // duplicates.
195 for (std::vector<std::string>::iterator I = Files.begin(),
196 E = Files.end(); I != E; ++I) {
197 // Start a new line if this would exceed the column limit. Make
198 // sure to leave space for a trailing " \" in case we need to
199 // break the line on the next iteration.
200 unsigned N = I->length();
201 if (Columns + (N + 1) + 2 > MaxColumns) {
202 OS << " \\\n ";
203 Columns = 2;
205 OS << " " << *I;
206 Columns += N + 1;
208 OS << "\n";
210 // Create phony targets if requested.
211 if (PhonyDependencyTarget) {
212 // Skip the first entry, this is always the input file itself.
213 for (std::vector<std::string>::iterator I = Files.begin() + 1,
214 E = Files.end(); I != E; ++I) {
215 OS << "\n";
216 OS << *I << ":\n";
221 DependencyFileCallback::DependencyFileCallback(const Preprocessor *PP,
222 const std::string &InputFile,
223 const std::string &DepFile,
224 const std::string &Target,
225 const char *&ErrStr)
226 : PP(PP), InputFile(InputFile), Target(Target) {
228 OS.open(DepFile.c_str());
229 if (OS.fail())
230 ErrStr = "Could not open dependency output file\n";
231 else
232 ErrStr = NULL;
234 Files.push_back(InputFile);
237 DependencyFileCallback::~DependencyFileCallback() {
238 if ((!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) ||
239 OS.fail())
240 return;
242 OutputDependencyFile();
243 OS.close();