blob: 3306f82aea718127ef3ba824e6ea873364401742 [file] [log] [blame]
Daniel Dunbar750c3582008-10-24 22:12:41 +00001//===--- 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
Ted Kremenekc2542b62009-03-31 18:58:14 +000014#include "clang-cc.h"
Daniel Dunbar750c3582008-10-24 22:12:41 +000015#include "clang/Basic/SourceManager.h"
Chris Lattnerb9c3f962009-01-27 07:57:44 +000016#include "clang/Basic/FileManager.h"
Daniel Dunbar750c3582008-10-24 22:12:41 +000017#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/System/Path.h"
23#include "llvm/Support/CommandLine.h"
24#include "llvm/Support/Compiler.h"
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +000025#include "llvm/Support/raw_ostream.h"
Daniel Dunbar750c3582008-10-24 22:12:41 +000026#include <string>
27
28using namespace clang;
29
30namespace {
31class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +000032 std::vector<std::string> Files;
33 llvm::StringSet<> FilesSet;
Daniel Dunbar750c3582008-10-24 22:12:41 +000034 const Preprocessor *PP;
Chris Lattner02fbb252009-01-11 19:28:34 +000035 std::vector<std::string> Targets;
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000036 llvm::raw_ostream *OS;
Eli Friedmanb5c8f8b2009-05-19 03:35:57 +000037 bool IncludeSystemHeaders;
38 bool PhonyTarget;
Daniel Dunbar750c3582008-10-24 22:12:41 +000039private:
40 bool FileMatchesDepCriteria(const char *Filename,
Chris Lattner9d728512008-10-27 01:19:25 +000041 SrcMgr::CharacteristicKind FileType);
Daniel Dunbar750c3582008-10-24 22:12:41 +000042 void OutputDependencyFile();
43
44public:
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000045 DependencyFileCallback(const Preprocessor *_PP,
46 llvm::raw_ostream *_OS,
Eli Friedmanb5c8f8b2009-05-19 03:35:57 +000047 const std::vector<std::string> &_Targets,
48 bool _IncludeSystemHeaders,
49 bool _PhonyTarget)
50 : PP(_PP), Targets(_Targets), OS(_OS),
51 IncludeSystemHeaders(_IncludeSystemHeaders), PhonyTarget(_PhonyTarget) {}
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000052
53 ~DependencyFileCallback() {
54 OutputDependencyFile();
55 OS->flush();
56 delete OS;
57 }
58
Daniel Dunbar750c3582008-10-24 22:12:41 +000059 virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
Chris Lattner9d728512008-10-27 01:19:25 +000060 SrcMgr::CharacteristicKind FileType);
Daniel Dunbar750c3582008-10-24 22:12:41 +000061};
62}
63
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000064
Daniel Dunbar750c3582008-10-24 22:12:41 +000065
Eli Friedmanb5c8f8b2009-05-19 03:35:57 +000066void clang::AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
67 std::vector<std::string> &Targets,
68 bool IncludeSystemHeaders,
69 bool PhonyTarget) {
70 assert(!Targets.empty() && "Target required for dependency generation");
Daniel Dunbar750c3582008-10-24 22:12:41 +000071
72 DependencyFileCallback *PPDep =
Eli Friedmanb5c8f8b2009-05-19 03:35:57 +000073 new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders,
74 PhonyTarget);
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000075 PP->setPPCallbacks(PPDep);
Daniel Dunbar750c3582008-10-24 22:12:41 +000076}
77
78/// FileMatchesDepCriteria - Determine whether the given Filename should be
79/// considered as a dependency.
80bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
Chris Lattner9d728512008-10-27 01:19:25 +000081 SrcMgr::CharacteristicKind FileType) {
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000082 if (strcmp("<built-in>", Filename) == 0)
83 return false;
Daniel Dunbar750c3582008-10-24 22:12:41 +000084
Eli Friedmanb5c8f8b2009-05-19 03:35:57 +000085 if (IncludeSystemHeaders)
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000086 return true;
87
88 return FileType == SrcMgr::C_User;
Daniel Dunbar750c3582008-10-24 22:12:41 +000089}
90
91void DependencyFileCallback::FileChanged(SourceLocation Loc,
92 FileChangeReason Reason,
Chris Lattner9d728512008-10-27 01:19:25 +000093 SrcMgr::CharacteristicKind FileType) {
Daniel Dunbar750c3582008-10-24 22:12:41 +000094 if (Reason != PPCallbacks::EnterFile)
95 return;
Chris Lattnerb9c3f962009-01-27 07:57:44 +000096
Daniel Dunbara5a7bd02009-03-30 00:34:04 +000097 // 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!
Chris Lattnerb9c3f962009-01-27 07:57:44 +0000100 SourceManager &SM = PP->getSourceManager();
101
Chris Lattnere86e4cd02009-01-28 05:42:38 +0000102 const FileEntry *FE =
103 SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
104 if (FE == 0) return;
105
106 const char *Filename = FE->getName();
Daniel Dunbar750c3582008-10-24 22:12:41 +0000107 if (!FileMatchesDepCriteria(Filename, FileType))
108 return;
109
110 // Remove leading "./"
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000111 if (Filename[0] == '.' && Filename[1] == '/')
Daniel Dunbar750c3582008-10-24 22:12:41 +0000112 Filename = &Filename[2];
113
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000114 if (FilesSet.insert(Filename))
115 Files.push_back(Filename);
Daniel Dunbar750c3582008-10-24 22:12:41 +0000116}
117
118void DependencyFileCallback::OutputDependencyFile() {
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000119 // Write out the dependency targets, trying to avoid overly long
120 // lines when possible. We try our best to emit exactly the same
121 // dependency file as GCC (4.2), assuming the included files are the
122 // same.
123 const unsigned MaxColumns = 75;
Chris Lattner02fbb252009-01-11 19:28:34 +0000124 unsigned Columns = 0;
125
126 for (std::vector<std::string>::iterator
127 I = Targets.begin(), E = Targets.end(); I != E; ++I) {
128 unsigned N = I->length();
129 if (Columns == 0) {
130 Columns += N;
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000131 *OS << *I;
Chris Lattner02fbb252009-01-11 19:28:34 +0000132 } else if (Columns + N + 2 > MaxColumns) {
133 Columns = N + 2;
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000134 *OS << " \\\n " << *I;
Chris Lattner02fbb252009-01-11 19:28:34 +0000135 } else {
136 Columns += N + 1;
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000137 *OS << ' ' << *I;
Chris Lattner02fbb252009-01-11 19:28:34 +0000138 }
139 }
140
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000141 *OS << ':';
Chris Lattner02fbb252009-01-11 19:28:34 +0000142 Columns += 1;
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000143
144 // Now add each dependency in the order it was seen, but avoiding
145 // duplicates.
146 for (std::vector<std::string>::iterator I = Files.begin(),
147 E = Files.end(); I != E; ++I) {
148 // Start a new line if this would exceed the column limit. Make
149 // sure to leave space for a trailing " \" in case we need to
150 // break the line on the next iteration.
151 unsigned N = I->length();
152 if (Columns + (N + 1) + 2 > MaxColumns) {
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000153 *OS << " \\\n ";
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000154 Columns = 2;
155 }
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000156 *OS << ' ' << *I;
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000157 Columns += N + 1;
Daniel Dunbar750c3582008-10-24 22:12:41 +0000158 }
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000159 *OS << '\n';
Daniel Dunbar750c3582008-10-24 22:12:41 +0000160
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000161 // Create phony targets if requested.
Eli Friedmanb5c8f8b2009-05-19 03:35:57 +0000162 if (PhonyTarget) {
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000163 // Skip the first entry, this is always the input file itself.
164 for (std::vector<std::string>::iterator I = Files.begin() + 1,
165 E = Files.end(); I != E; ++I) {
Daniel Dunbara5a7bd02009-03-30 00:34:04 +0000166 *OS << '\n';
167 *OS << *I << ":\n";
Daniel Dunbar7e9f1f72008-10-27 20:01:06 +0000168 }
169 }
Daniel Dunbar750c3582008-10-24 22:12:41 +0000170}
171