 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
56.5% |
26 / 46 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
78.3% |
36 / 46 |
| |
|
Line Coverage: |
75.0% |
51 / 68 |
| |
 |
|
 |
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.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "clang/Frontend/Utils.h"
15 : #include "clang/Basic/FileManager.h"
16 : #include "clang/Basic/SourceLocation.h"
17 : #include "clang/Basic/SourceManager.h"
18 : #include "clang/Frontend/DependencyOutputOptions.h"
19 : #include "clang/Frontend/FrontendDiagnostic.h"
20 : #include "clang/Lex/DirectoryLookup.h"
21 : #include "clang/Lex/PPCallbacks.h"
22 : #include "clang/Lex/Preprocessor.h"
23 : #include "llvm/ADT/StringSet.h"
24 : #include "llvm/Support/raw_ostream.h"
25 : #include <string>
26 :
27 : using namespace clang;
28 :
29 : namespace {
30 : class DependencyFileCallback : public PPCallbacks {
31 : std::vector<std::string> Files;
32 : llvm::StringSet<> FilesSet;
33 : const Preprocessor *PP;
34 : std::vector<std::string> Targets;
35 : llvm::raw_ostream *OS;
36 : bool IncludeSystemHeaders;
37 : bool PhonyTarget;
38 : private:
39 : bool FileMatchesDepCriteria(const char *Filename,
40 : SrcMgr::CharacteristicKind FileType);
41 : void OutputDependencyFile();
42 :
43 : public:
44 : DependencyFileCallback(const Preprocessor *_PP,
45 : llvm::raw_ostream *_OS,
46 3: const DependencyOutputOptions &Opts)
47 : : PP(_PP), Targets(Opts.Targets), OS(_OS),
48 : IncludeSystemHeaders(Opts.IncludeSystemHeaders),
49 3: PhonyTarget(Opts.UsePhonyTargets) {}
50 :
51 3: ~DependencyFileCallback() {
52 3: OutputDependencyFile();
53 3: OS->flush();
3: branch 0 taken
0: branch 1 not taken
3: branch 3 taken
3: branch 4 taken
54 3: delete OS;
3: branch 4 taken
0: branch 5 not taken
0: branch 11 not taken
0: branch 12 not taken
55 3: }
56 :
57 : virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
58 : SrcMgr::CharacteristicKind FileType);
59 : };
60 : }
61 :
62 : void clang::AttachDependencyFileGen(Preprocessor &PP,
63 3: const DependencyOutputOptions &Opts) {
0: branch 1 not taken
3: branch 2 taken
64 3: if (Opts.Targets.empty()) {
65 0: PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
66 0: return;
67 : }
68 :
69 3: std::string Err;
70 3: llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err));
0: branch 1 not taken
3: branch 2 taken
71 3: if (!Err.empty()) {
72 : PP.getDiagnostics().Report(diag::err_fe_error_opening)
73 0: << Opts.OutputFile << Err;
74 0: return;
75 : }
76 :
3: branch 1 taken
0: branch 2 not taken
77 3: assert(!PP.getPPCallbacks() && "Preprocessor callbacks already registered!");
3: branch 4 taken
0: branch 5 not taken
78 6: PP.setPPCallbacks(new DependencyFileCallback(&PP, OS, Opts));
79 : }
80 :
81 : /// FileMatchesDepCriteria - Determine whether the given Filename should be
82 : /// considered as a dependency.
83 : bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
84 3: SrcMgr::CharacteristicKind FileType) {
0: branch 1 not taken
3: branch 2 taken
85 3: if (strcmp("<built-in>", Filename) == 0)
86 0: return false;
87 :
3: branch 0 taken
0: branch 1 not taken
88 3: if (IncludeSystemHeaders)
89 3: return true;
90 :
91 0: return FileType == SrcMgr::C_User;
92 : }
93 :
94 : void DependencyFileCallback::FileChanged(SourceLocation Loc,
95 : FileChangeReason Reason,
96 18: SrcMgr::CharacteristicKind FileType) {
9: branch 0 taken
9: branch 1 taken
97 18: if (Reason != PPCallbacks::EnterFile)
98 9: return;
99 :
100 : // Dependency generation really does want to go all the way to the
101 : // file entry for a source location to find out what is depended on.
102 : // We do not want #line markers to affect dependency generation!
103 9: SourceManager &SM = PP->getSourceManager();
104 :
105 : const FileEntry *FE =
106 9: SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
3: branch 0 taken
6: branch 1 taken
107 9: if (FE == 0) return;
108 :
109 3: const char *Filename = FE->getName();
0: branch 1 not taken
3: branch 2 taken
110 3: if (!FileMatchesDepCriteria(Filename, FileType))
111 0: return;
112 :
113 : // Remove leading "./"
0: branch 0 not taken
3: branch 1 taken
3: branch 2 taken
3: branch 3 taken
114 3: if (Filename[0] == '.' && Filename[1] == '/')
115 0: Filename = &Filename[2];
116 :
3: branch 5 taken
0: branch 6 not taken
117 3: if (FilesSet.insert(Filename))
118 3: Files.push_back(Filename);
119 : }
120 :
121 3: void DependencyFileCallback::OutputDependencyFile() {
122 : // Write out the dependency targets, trying to avoid overly long
123 : // lines when possible. We try our best to emit exactly the same
124 : // dependency file as GCC (4.2), assuming the included files are the
125 : // same.
126 3: const unsigned MaxColumns = 75;
127 3: unsigned Columns = 0;
128 :
3: branch 2 taken
3: branch 3 taken
129 6: for (std::vector<std::string>::iterator
130 3: I = Targets.begin(), E = Targets.end(); I != E; ++I) {
131 3: unsigned N = I->length();
3: branch 0 taken
0: branch 1 not taken
132 3: if (Columns == 0) {
133 3: Columns += N;
134 3: *OS << *I;
0: branch 0 not taken
0: branch 1 not taken
135 0: } else if (Columns + N + 2 > MaxColumns) {
136 0: Columns = N + 2;
137 0: *OS << " \\\n " << *I;
138 : } else {
139 0: Columns += N + 1;
140 0: *OS << ' ' << *I;
141 : }
142 : }
143 :
144 3: *OS << ':';
145 3: Columns += 1;
146 :
147 : // Now add each dependency in the order it was seen, but avoiding
148 : // duplicates.
3: branch 3 taken
3: branch 4 taken
149 9: for (std::vector<std::string>::iterator I = Files.begin(),
150 3: E = Files.end(); I != E; ++I) {
151 : // Start a new line if this would exceed the column limit. Make
152 : // sure to leave space for a trailing " \" in case we need to
153 : // break the line on the next iteration.
154 3: unsigned N = I->length();
3: branch 0 taken
0: branch 1 not taken
155 3: if (Columns + (N + 1) + 2 > MaxColumns) {
156 3: *OS << " \\\n ";
157 3: Columns = 2;
158 : }
159 3: *OS << ' ' << *I;
160 3: Columns += N + 1;
161 : }
162 3: *OS << '\n';
163 :
164 : // Create phony targets if requested.
0: branch 0 not taken
3: branch 1 taken
165 3: if (PhonyTarget) {
166 : // Skip the first entry, this is always the input file itself.
0: branch 4 not taken
0: branch 5 not taken
167 0: for (std::vector<std::string>::iterator I = Files.begin() + 1,
168 0: E = Files.end(); I != E; ++I) {
169 0: *OS << '\n';
170 0: *OS << *I << ":\n";
171 : }
172 : }
173 3: }
174 :
Generated: 2010-02-10 01:31 by zcov