1 //===--- DependencyFile.cpp - Generate dependency file --------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This code generates dependency files.
12 //===----------------------------------------------------------------------===//
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"
28 using namespace clang
;
31 class VISIBILITY_HIDDEN DependencyFileCallback
: public PPCallbacks
{
32 std::vector
<std::string
> Files
;
33 llvm::StringSet
<> FilesSet
;
34 const Preprocessor
*PP
;
36 const std::string
&InputFile
;
40 bool FileMatchesDepCriteria(const char *Filename
,
41 SrcMgr::CharacteristicKind FileType
);
42 void OutputDependencyFile();
45 DependencyFileCallback(const Preprocessor
*PP
,
46 const std::string
&InputFile
,
47 const std::string
&DepFile
,
48 const std::string
&Target
,
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");
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";
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
);
116 DepFile
.eraseSuffix();
117 DepFile
.appendSuffix(DependencyFileExt
);
120 // Determine name of 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();
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(),
145 PP
->setPPCallbacks(PPDep
);
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
;
165 void DependencyFileCallback::FileChanged(SourceLocation Loc
,
166 FileChangeReason Reason
,
167 SrcMgr::CharacteristicKind FileType
) {
168 if (Reason
!= PPCallbacks::EnterFile
)
171 const char *Filename
= PP
->getSourceManager().getSourceName(Loc
);
172 if (!FileMatchesDepCriteria(Filename
, FileType
))
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
188 const unsigned MaxColumns
= 75;
191 unsigned Columns
= Target
.length() + 1;
193 // Now add each dependency in the order it was seen, but avoiding
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
) {
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
) {
221 DependencyFileCallback::DependencyFileCallback(const Preprocessor
*PP
,
222 const std::string
&InputFile
,
223 const std::string
&DepFile
,
224 const std::string
&Target
,
226 : PP(PP
), InputFile(InputFile
), Target(Target
) {
228 OS
.open(DepFile
.c_str());
230 ErrStr
= "Could not open dependency output file\n";
234 Files
.push_back(InputFile
);
237 DependencyFileCallback::~DependencyFileCallback() {
238 if ((!GenerateDependencyFile
&& !GenerateDependencyFileNoSysHeaders
) ||
242 OutputDependencyFile();