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 //===----------------------------------------------------------------------===//
14 #include "clang/Frontend/Utils.h"
15 #include "clang/Basic/FileManager.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Frontend/DependencyOutputOptions.h"
18 #include "clang/Frontend/FrontendDiagnostic.h"
19 #include "clang/Lex/DirectoryLookup.h"
20 #include "clang/Lex/PPCallbacks.h"
21 #include "clang/Lex/Preprocessor.h"
22 #include "llvm/ADT/StringSet.h"
23 #include "llvm/Support/raw_ostream.h"
25 using namespace clang
;
28 class DependencyFileCallback
: public PPCallbacks
{
29 std::vector
<std::string
> Files
;
30 llvm::StringSet
<> FilesSet
;
31 const Preprocessor
*PP
;
32 std::vector
<std::string
> Targets
;
33 llvm::raw_ostream
*OS
;
34 bool IncludeSystemHeaders
;
37 bool FileMatchesDepCriteria(const char *Filename
,
38 SrcMgr::CharacteristicKind FileType
);
39 void OutputDependencyFile();
42 DependencyFileCallback(const Preprocessor
*_PP
,
43 llvm::raw_ostream
*_OS
,
44 const DependencyOutputOptions
&Opts
)
45 : PP(_PP
), Targets(Opts
.Targets
), OS(_OS
),
46 IncludeSystemHeaders(Opts
.IncludeSystemHeaders
),
47 PhonyTarget(Opts
.UsePhonyTargets
) {}
49 virtual void FileChanged(SourceLocation Loc
, FileChangeReason Reason
,
50 SrcMgr::CharacteristicKind FileType
);
52 virtual void EndOfMainFile() {
53 OutputDependencyFile();
60 void clang::AttachDependencyFileGen(Preprocessor
&PP
,
61 const DependencyOutputOptions
&Opts
) {
62 if (Opts
.Targets
.empty()) {
63 PP
.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT
);
68 llvm::raw_ostream
*OS(new llvm::raw_fd_ostream(Opts
.OutputFile
.c_str(), Err
));
70 PP
.getDiagnostics().Report(diag::err_fe_error_opening
)
71 << Opts
.OutputFile
<< Err
;
75 PP
.addPPCallbacks(new DependencyFileCallback(&PP
, OS
, Opts
));
78 /// FileMatchesDepCriteria - Determine whether the given Filename should be
79 /// considered as a dependency.
80 bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename
,
81 SrcMgr::CharacteristicKind FileType
) {
82 if (strcmp("<built-in>", Filename
) == 0)
85 if (IncludeSystemHeaders
)
88 return FileType
== SrcMgr::C_User
;
91 void DependencyFileCallback::FileChanged(SourceLocation Loc
,
92 FileChangeReason Reason
,
93 SrcMgr::CharacteristicKind FileType
) {
94 if (Reason
!= PPCallbacks::EnterFile
)
97 // Dependency generation really does want to go all the way to the
98 // file entry for a source location to find out what is depended on.
99 // We do not want #line markers to affect dependency generation!
100 SourceManager
&SM
= PP
->getSourceManager();
102 const FileEntry
*FE
=
103 SM
.getFileEntryForID(SM
.getFileID(SM
.getInstantiationLoc(Loc
)));
106 const char *Filename
= FE
->getName();
107 if (!FileMatchesDepCriteria(Filename
, FileType
))
110 // Remove leading "./"
111 if (Filename
[0] == '.' && Filename
[1] == '/')
112 Filename
= &Filename
[2];
114 if (FilesSet
.insert(Filename
))
115 Files
.push_back(Filename
);
118 /// PrintFilename - GCC escapes spaces, but apparently not ' or " or other
119 /// scary characters.
120 static void PrintFilename(llvm::raw_ostream
&OS
, llvm::StringRef Filename
) {
121 for (unsigned i
= 0, e
= Filename
.size(); i
!= e
; ++i
) {
122 if (Filename
[i
] == ' ')
128 void DependencyFileCallback::OutputDependencyFile() {
129 // Write out the dependency targets, trying to avoid overly long
130 // lines when possible. We try our best to emit exactly the same
131 // dependency file as GCC (4.2), assuming the included files are the
133 const unsigned MaxColumns
= 75;
134 unsigned Columns
= 0;
136 for (std::vector
<std::string
>::iterator
137 I
= Targets
.begin(), E
= Targets
.end(); I
!= E
; ++I
) {
138 unsigned N
= I
->length();
141 } else if (Columns
+ N
+ 2 > MaxColumns
) {
148 // Targets already quoted as needed.
155 // Now add each dependency in the order it was seen, but avoiding
157 for (std::vector
<std::string
>::iterator I
= Files
.begin(),
158 E
= Files
.end(); I
!= E
; ++I
) {
159 // Start a new line if this would exceed the column limit. Make
160 // sure to leave space for a trailing " \" in case we need to
161 // break the line on the next iteration.
162 unsigned N
= I
->length();
163 if (Columns
+ (N
+ 1) + 2 > MaxColumns
) {
168 PrintFilename(*OS
, *I
);
173 // Create phony targets if requested.
175 // Skip the first entry, this is always the input file itself.
176 for (std::vector
<std::string
>::iterator I
= Files
.begin() + 1,
177 E
= Files
.end(); I
!= E
; ++I
) {
179 PrintFilename(*OS
, *I
);