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