blob: afc03d49bd5e501dac5f9198b7566c528a9f1acd [file] [log] [blame]
John Thompsond845bae2015-02-13 14:29:22 +00001//===--- extra/modularize/ModularizeUtilities.cpp -------------------===//
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 file implements a class for loading and validating a module map or
11// header list by checking that all headers in the corresponding directories
12// are accounted for.
13//
14//===----------------------------------------------------------------------===//
15
16#include "ModularizeUtilities.h"
John Thompson9cb79642015-02-18 16:14:32 +000017#include "clang/Basic/SourceManager.h"
18#include "clang/Driver/Options.h"
19#include "clang/Frontend/CompilerInstance.h"
20#include "clang/Frontend/FrontendActions.h"
John Thompsond845bae2015-02-13 14:29:22 +000021#include "llvm/ADT/SmallString.h"
22#include "llvm/Support/FileUtilities.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/Support/Path.h"
25#include "llvm/Support/raw_ostream.h"
26
John Thompson9cb79642015-02-18 16:14:32 +000027using namespace clang;
John Thompsond845bae2015-02-13 14:29:22 +000028using namespace llvm;
29using namespace Modularize;
30
John Thompson9cb79642015-02-18 16:14:32 +000031// Subclass TargetOptions so we can construct it inline with
32// the minimal option, the triple.
33class ModuleMapTargetOptions : public clang::TargetOptions {
34public:
35 ModuleMapTargetOptions() { Triple = llvm::sys::getDefaultTargetTriple(); }
36};
37
John Thompsond845bae2015-02-13 14:29:22 +000038// ModularizeUtilities class implementation.
39
40// Constructor.
41ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
42 llvm::StringRef Prefix)
John Thompson9cb79642015-02-18 16:14:32 +000043 : InputFilePaths(InputPaths),
44 HeaderPrefix(Prefix),
45 // Init clang stuff needed for loading the module map and preprocessing.
46 LangOpts(new LangOptions()), DiagIDs(new DiagnosticIDs()),
47 DiagnosticOpts(new DiagnosticOptions()),
48 DC(llvm::errs(), DiagnosticOpts.get()),
49 Diagnostics(
50 new DiagnosticsEngine(DiagIDs, DiagnosticOpts.get(), &DC, false)),
51 TargetOpts(new ModuleMapTargetOptions()),
52 Target(TargetInfo::CreateTargetInfo(*Diagnostics, TargetOpts)),
53 FileMgr(new FileManager(FileSystemOpts)),
54 SourceMgr(new SourceManager(*Diagnostics, *FileMgr, false)),
55 HeaderSearchOpts(new HeaderSearchOptions()),
56 HeaderInfo(new HeaderSearch(HeaderSearchOpts, *SourceMgr, *Diagnostics,
57 *LangOpts, Target.get())) {
58}
John Thompsond845bae2015-02-13 14:29:22 +000059
60// Create instance of ModularizeUtilities, to simplify setting up
61// subordinate objects.
62ModularizeUtilities *ModularizeUtilities::createModularizeUtilities(
63 std::vector<std::string> &InputPaths, llvm::StringRef Prefix) {
64
65 return new ModularizeUtilities(InputPaths, Prefix);
66}
67
68// Load all header lists and dependencies.
69std::error_code ModularizeUtilities::loadAllHeaderListsAndDependencies() {
70 typedef std::vector<std::string>::iterator Iter;
John Thompson9cb79642015-02-18 16:14:32 +000071 // For each input file.
John Thompsond845bae2015-02-13 14:29:22 +000072 for (Iter I = InputFilePaths.begin(), E = InputFilePaths.end(); I != E; ++I) {
John Thompson9cb79642015-02-18 16:14:32 +000073 llvm::StringRef InputPath = *I;
74 // If it's a module map.
75 if (InputPath.endswith(".modulemap")) {
76 // Load the module map.
77 if (std::error_code EC = loadModuleMap(InputPath))
78 return EC;
79 }
80 else {
81 // Else we assume it's a header list and load it.
82 if (std::error_code EC = loadSingleHeaderListsAndDependencies(InputPath)) {
83 errs() << "modularize: error: Unable to get header list '" << InputPath
84 << "': " << EC.message() << '\n';
85 return EC;
86 }
John Thompsond845bae2015-02-13 14:29:22 +000087 }
88 }
89 return std::error_code();
90}
91
92// Load single header list and dependencies.
93std::error_code ModularizeUtilities::loadSingleHeaderListsAndDependencies(
94 llvm::StringRef InputPath) {
95
96 // By default, use the path component of the list file name.
97 SmallString<256> HeaderDirectory(InputPath);
98 llvm::sys::path::remove_filename(HeaderDirectory);
99 SmallString<256> CurrentDirectory;
100 llvm::sys::fs::current_path(CurrentDirectory);
101
102 // Get the prefix if we have one.
103 if (HeaderPrefix.size() != 0)
104 HeaderDirectory = HeaderPrefix;
105
106 // Read the header list file into a buffer.
107 ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
108 MemoryBuffer::getFile(InputPath);
109 if (std::error_code EC = listBuffer.getError())
110 return EC;
111
112 // Parse the header list into strings.
113 SmallVector<StringRef, 32> Strings;
114 listBuffer.get()->getBuffer().split(Strings, "\n", -1, false);
115
116 // Collect the header file names from the string list.
117 for (SmallVectorImpl<StringRef>::iterator I = Strings.begin(),
118 E = Strings.end();
119 I != E; ++I) {
120 StringRef Line = I->trim();
121 // Ignore comments and empty lines.
122 if (Line.empty() || (Line[0] == '#'))
123 continue;
124 std::pair<StringRef, StringRef> TargetAndDependents = Line.split(':');
125 SmallString<256> HeaderFileName;
126 // Prepend header file name prefix if it's not absolute.
127 if (llvm::sys::path::is_absolute(TargetAndDependents.first))
128 llvm::sys::path::native(TargetAndDependents.first, HeaderFileName);
129 else {
130 if (HeaderDirectory.size() != 0)
131 HeaderFileName = HeaderDirectory;
132 else
133 HeaderFileName = CurrentDirectory;
134 llvm::sys::path::append(HeaderFileName, TargetAndDependents.first);
135 llvm::sys::path::native(HeaderFileName);
136 }
137 // Handle optional dependencies.
138 DependentsVector Dependents;
139 SmallVector<StringRef, 4> DependentsList;
140 TargetAndDependents.second.split(DependentsList, " ", -1, false);
141 int Count = DependentsList.size();
142 for (int Index = 0; Index < Count; ++Index) {
143 SmallString<256> Dependent;
144 if (llvm::sys::path::is_absolute(DependentsList[Index]))
145 Dependent = DependentsList[Index];
146 else {
147 if (HeaderDirectory.size() != 0)
148 Dependent = HeaderDirectory;
149 else
150 Dependent = CurrentDirectory;
151 llvm::sys::path::append(Dependent, DependentsList[Index]);
152 }
153 llvm::sys::path::native(Dependent);
John Thompson3dcb3932015-02-17 20:43:47 +0000154 Dependents.push_back(getCanonicalPath(Dependent.str()));
John Thompsond845bae2015-02-13 14:29:22 +0000155 }
John Thompson3dcb3932015-02-17 20:43:47 +0000156 // Get canonical form.
157 HeaderFileName = getCanonicalPath(HeaderFileName);
John Thompsond845bae2015-02-13 14:29:22 +0000158 // Save the resulting header file path and dependencies.
159 HeaderFileNames.push_back(HeaderFileName.str());
160 Dependencies[HeaderFileName.str()] = Dependents;
161 }
162 return std::error_code();
163}
John Thompson3dcb3932015-02-17 20:43:47 +0000164
John Thompson9cb79642015-02-18 16:14:32 +0000165// Load single module map and extract header file list.
166std::error_code ModularizeUtilities::loadModuleMap(
167 llvm::StringRef InputPath) {
168 // Get file entry for module.modulemap file.
169 const FileEntry *ModuleMapEntry =
170 SourceMgr->getFileManager().getFile(InputPath);
171
172 // return error if not found.
173 if (!ModuleMapEntry) {
174 llvm::errs() << "error: File \"" << InputPath << "\" not found.\n";
175 return std::error_code(1, std::generic_category());
176 }
177
178 // Because the module map parser uses a ForwardingDiagnosticConsumer,
179 // which doesn't forward the BeginSourceFile call, we do it explicitly here.
180 DC.BeginSourceFile(*LangOpts, nullptr);
181
182 // Figure out the home directory for the module map file.
183 const DirectoryEntry *Dir = ModuleMapEntry->getDir();
184 StringRef DirName(Dir->getName());
185 if (llvm::sys::path::filename(DirName) == "Modules") {
186 DirName = llvm::sys::path::parent_path(DirName);
187 if (DirName.endswith(".framework"))
188 Dir = FileMgr->getDirectory(DirName);
189 // FIXME: This assert can fail if there's a race between the above check
190 // and the removal of the directory.
191 assert(Dir && "parent must exist");
192 }
193
194 std::unique_ptr<ModuleMap> ModMap;
195 ModMap.reset(new ModuleMap(*SourceMgr, *Diagnostics, *LangOpts,
196 Target.get(), *HeaderInfo));
197
198 // Parse module.modulemap file into module map.
199 if (ModMap->parseModuleMapFile(ModuleMapEntry, false, Dir)) {
200 return std::error_code(1, std::generic_category());
201 }
202
203 // Do matching end call.
204 DC.EndSourceFile();
205
206 if (!collectModuleMapHeaders(ModMap.get()))
207 return std::error_code(1, std::generic_category());
208
209 // Save module map.
210 ModuleMaps.push_back(std::move(ModMap));
211
212 return std::error_code();
213}
214
215// Collect module map headers.
216// Walks the modules and collects referenced headers into
John Thompson3c9fb522015-02-19 14:31:48 +0000217// HeaderFileNames.
John Thompson9cb79642015-02-18 16:14:32 +0000218bool ModularizeUtilities::collectModuleMapHeaders(clang::ModuleMap *ModMap) {
219 for (ModuleMap::module_iterator I = ModMap->module_begin(),
220 E = ModMap->module_end();
221 I != E; ++I) {
222 if (!collectModuleHeaders(*I->second))
223 return false;
224 }
225 return true;
226}
227
228// Collect referenced headers from one module.
229// Collects the headers referenced in the given module into
John Thompson3c9fb522015-02-19 14:31:48 +0000230// HeaderFileNames.
John Thompson9cb79642015-02-18 16:14:32 +0000231bool ModularizeUtilities::collectModuleHeaders(const Module &Mod) {
232
233 // Ignore explicit modules because they often have dependencies
234 // we can't know.
235 if (Mod.IsExplicit)
236 return true;
237
238 // Treat headers in umbrella directory as dependencies.
239 DependentsVector UmbrellaDependents;
240
241 // Recursively do submodules.
242 for (Module::submodule_const_iterator MI = Mod.submodule_begin(),
243 MIEnd = Mod.submodule_end();
244 MI != MIEnd; ++MI)
245 collectModuleHeaders(**MI);
246
247 if (const FileEntry *UmbrellaHeader = Mod.getUmbrellaHeader()) {
248 std::string HeaderPath = getCanonicalPath(UmbrellaHeader->getName());
249 // Collect umbrella header.
250 HeaderFileNames.push_back(HeaderPath);
John Thompson9cb79642015-02-18 16:14:32 +0000251
252 // FUTURE: When needed, umbrella header header collection goes here.
253 }
254 else if (const DirectoryEntry *UmbrellaDir = Mod.getUmbrellaDir()) {
255 // If there normal headers, assume these are umbrellas and skip collection.
256 if (Mod.Headers->size() == 0) {
257 // Collect headers in umbrella directory.
258 if (!collectUmbrellaHeaders(UmbrellaDir->getName(), UmbrellaDependents))
259 return false;
260 }
261 }
262
263 // We ignore HK_Private, HK_Textual, HK_PrivateTextual, and HK_Excluded,
264 // assuming they are marked as such either because of unsuitability for
265 // modules or because they are meant to be included by another header,
266 // and thus should be ignored by modularize.
267
268 int NormalHeaderCount = Mod.Headers[clang::Module::HK_Normal].size();
269
270 for (int Index = 0; Index < NormalHeaderCount; ++Index) {
271 DependentsVector NormalDependents;
272 // Collect normal header.
273 const clang::Module::Header &Header(
274 Mod.Headers[clang::Module::HK_Normal][Index]);
275 std::string HeaderPath = getCanonicalPath(Header.Entry->getName());
276 HeaderFileNames.push_back(HeaderPath);
277 }
278
279 return true;
280}
281
282// Collect headers from an umbrella directory.
283bool ModularizeUtilities::collectUmbrellaHeaders(StringRef UmbrellaDirName,
284 DependentsVector &Dependents) {
285 // Initialize directory name.
286 SmallString<256> Directory(UmbrellaDirName);
287 // Walk the directory.
288 std::error_code EC;
289 llvm::sys::fs::file_status Status;
290 for (llvm::sys::fs::directory_iterator I(Directory.str(), EC), E; I != E;
291 I.increment(EC)) {
292 if (EC)
293 return false;
294 std::string File(I->path());
295 I->status(Status);
296 llvm::sys::fs::file_type Type = Status.type();
297 // If the file is a directory, ignore the name and recurse.
298 if (Type == llvm::sys::fs::file_type::directory_file) {
299 if (!collectUmbrellaHeaders(File, Dependents))
300 return false;
301 continue;
302 }
303 // If the file does not have a common header extension, ignore it.
304 if (!isHeader(File))
305 continue;
306 // Save header name.
307 std::string HeaderPath = getCanonicalPath(File);
John Thompson9cb79642015-02-18 16:14:32 +0000308 Dependents.push_back(HeaderPath);
309 }
310 return true;
311}
312
John Thompson3dcb3932015-02-17 20:43:47 +0000313// Convert header path to canonical form.
314// The canonical form is basically just use forward slashes, and remove "./".
315// \param FilePath The file path, relative to the module map directory.
316// \returns The file path in canonical form.
317std::string ModularizeUtilities::getCanonicalPath(StringRef FilePath) {
318 std::string Tmp(FilePath);
319 std::replace(Tmp.begin(), Tmp.end(), '\\', '/');
320 StringRef Tmp2(Tmp);
321 if (Tmp2.startswith("./"))
322 Tmp = Tmp2.substr(2);
323 return Tmp;
324}
John Thompson9cb79642015-02-18 16:14:32 +0000325
326// Check for header file extension.
327// If the file extension is .h, .inc, or missing, it's
328// assumed to be a header.
329// \param FileName The file name. Must not be a directory.
330// \returns true if it has a header extension or no extension.
331bool ModularizeUtilities::isHeader(StringRef FileName) {
332 StringRef Extension = llvm::sys::path::extension(FileName);
333 if (Extension.size() == 0)
334 return false;
335 if (Extension.equals_lower(".h"))
336 return true;
337 if (Extension.equals_lower(".inc"))
338 return true;
339 return false;
340}