blob: 45641cb943e15ace566bbd7b5959207c0f4089b8 [file] [log] [blame]
John Thompson5ab4f112013-10-15 13:52:33 +00001//===--- ModuleAssistant.cpp - Module map generation manager -*- C++ -*---===//
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 defines the module generation entry point function,
11// createModuleMap, a Module class for representing a module,
12// and various implementation functions for doing the underlying
13// work, described below.
14//
15// The "Module" class represents a module, with members for storing the module
16// name, associated header file names, and sub-modules, and an "output"
17// function that recursively writes the module definitions.
18//
19// The "createModuleMap" function implements the top-level logic of the
20// assistant mode. It calls a loadModuleDescriptions function to walk
21// the header list passed to it and creates a tree of Module objects
22// representing the module hierarchy, represented by a "Module" object,
23// the "RootModule". This root module may or may not represent an actual
24// module in the module map, depending on the "--root-module" option passed
25// to modularize. It then calls a writeModuleMap function to set up the
26// module map file output and walk the module tree, outputting the module
27// map file using a stream obtained and managed by an
28// llvm::tool_output_file object.
29//
30//===---------------------------------------------------------------------===//
31
32#include "Modularize.h"
33#include "llvm/ADT/OwningPtr.h"
34#include "llvm/ADT/SmallString.h"
35#include "llvm/Support/FileSystem.h"
36#include "llvm/Support/Path.h"
37#include "llvm/Support/ToolOutputFile.h"
38#include <vector>
39
40// Local definitions:
41
42namespace {
43
44// Internal class definitions:
45
46// Represents a module.
47class Module {
48public:
49 Module(llvm::StringRef Name);
50 Module();
51 ~Module();
52 bool output(llvm::raw_fd_ostream &OS, int Indent);
53 Module *findSubModule(llvm::StringRef SubName);
54
55public:
56 std::string Name;
57 std::vector<std::string> HeaderFileNames;
58 std::vector<Module *> SubModules;
59};
60
61} // end anonymous namespace.
62
63// Module functions:
64
65// Constructors.
66Module::Module(llvm::StringRef Name) : Name(Name) {}
67Module::Module() {}
68
69// Destructor.
70Module::~Module() {
71 // Free submodules.
72 while (SubModules.size()) {
73 Module *last = SubModules.back();
74 SubModules.pop_back();
75 delete last;
76 }
77}
78
79// Write a module hierarchy to the given output stream.
80bool Module::output(llvm::raw_fd_ostream &OS, int Indent) {
81 // If this is not the nameless root module, start a module definition.
82 if (Name.size() != 0) {
83 OS.indent(Indent);
84 OS << "module " << Name << " {\n";
85 Indent += 2;
86 }
87
88 // Output submodules.
89 for (std::vector<Module *>::iterator I = SubModules.begin(),
90 E = SubModules.end();
91 I != E; ++I) {
92 if (!(*I)->output(OS, Indent))
93 return false;
94 }
95
96 // Output header files.
97 for (std::vector<std::string>::iterator I = HeaderFileNames.begin(),
98 E = HeaderFileNames.end();
99 I != E; ++I) {
100 OS.indent(Indent);
101 OS << "header \"" << *I << "\"\n";
102 }
103
104 // If this module has header files, output export directive.
105 if (HeaderFileNames.size() != 0) {
106 OS.indent(Indent);
107 OS << "export *\n";
108 }
109
110 // If this is not the nameless root module, close the module definition.
111 if (Name.size() != 0) {
112 Indent -= 2;
113 OS.indent(Indent);
114 OS << "}\n";
115 }
116
117 return true;
118}
119
120// Lookup a sub-module.
121Module *Module::findSubModule(llvm::StringRef SubName) {
122 for (std::vector<Module *>::iterator I = SubModules.begin(),
123 E = SubModules.end();
124 I != E; ++I) {
125 if ((*I)->Name == SubName)
126 return *I;
127 }
128 return 0;
129}
130
131// Implementation functions:
132
133// Reserved keywords in module.map syntax.
134// Keep in sync with keywords in module map parser in Lex/ModuleMap.cpp,
135// such as in ModuleMapParser::consumeToken().
136static const char *ReservedNames[] = {
137 "config_macros", "export", "module", "conflict", "framework",
138 "requires", "exclude", "header", "private", "explicit",
139 "link", "umbrella", "extern", "use", 0 // Flag end.
140};
141
142// Convert module name to a non keyword.
143// Prepends a '_' to the name if and only if the name is a keyword.
144static std::string
145ensureNoCollisionWithReservedName(llvm::StringRef MightBeReservedName) {
146 std::string SafeName = MightBeReservedName;
147 for (int Index = 0; ReservedNames[Index] != 0; ++Index) {
148 if (MightBeReservedName == ReservedNames[Index]) {
149 SafeName.insert(0, "_");
150 break;
151 }
152 }
153 return SafeName;
154}
155
156// Add one module, given a header file path.
157static bool addModuleDescription(Module *RootModule,
158 llvm::StringRef HeaderFilePath,
159 llvm::StringRef HeaderPrefix,
160 DependencyMap &Dependencies) {
161 Module *CurrentModule = RootModule;
162 DependentsVector &FileDependents = Dependencies[HeaderFilePath];
163 std::string FilePath;
164 // Strip prefix.
165 if (HeaderFilePath.startswith(HeaderPrefix))
166 FilePath = HeaderFilePath.substr(HeaderPrefix.size() + 1);
167 else
168 FilePath = HeaderFilePath;
169 int Count = FileDependents.size();
170 // Headers that go into modules must not depend on other files being
171 // included first. If there are any dependents, warn user and omit.
172 if (Count != 0) {
173 llvm::errs() << "warning: " << FilePath
174 << " depends on other headers being included first,"
175 " meaning the module.map won't compile."
176 " This header will be omitted from the module map.\n";
177 return true;
178 }
179 // Make canonical.
180 std::replace(FilePath.begin(), FilePath.end(), '\\', '/');
181 // Insert module into tree, using subdirectories as submodules.
182 for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(FilePath),
183 E = llvm::sys::path::end(FilePath);
184 I != E; ++I) {
185 if ((*I)[0] == '.')
186 continue;
187 std::string Stem = llvm::sys::path::stem(*I);
188 Stem = ensureNoCollisionWithReservedName(Stem);
189 Module *SubModule = CurrentModule->findSubModule(Stem);
190 if (SubModule == 0) {
191 SubModule = new Module(Stem);
192 CurrentModule->SubModules.push_back(SubModule);
193 }
194 CurrentModule = SubModule;
195 }
196 // Add header file name to headers.
197 CurrentModule->HeaderFileNames.push_back(FilePath);
198 return true;
199}
200
201// Create the internal module tree representation.
202static Module *loadModuleDescriptions(
203 llvm::StringRef RootModuleName, llvm::ArrayRef<std::string> HeaderFileNames,
204 DependencyMap &Dependencies, llvm::StringRef HeaderPrefix) {
205
206 // Create root module.
207 Module *RootModule = new Module(RootModuleName);
208
209 llvm::SmallString<256> CurrentDirectory;
210 llvm::sys::fs::current_path(CurrentDirectory);
211
212 // If no header prefix, use current directory.
213 if (HeaderPrefix.size() == 0)
214 HeaderPrefix = CurrentDirectory;
215
216 // Walk the header file names and output the module map.
217 for (llvm::ArrayRef<std::string>::iterator I = HeaderFileNames.begin(),
218 E = HeaderFileNames.end();
219 I != E; ++I) {
220 // Add as a module.
221 if (!addModuleDescription(RootModule, *I, HeaderPrefix, Dependencies))
Will Dietz0f3b4aa2013-10-15 15:45:00 +0000222 return NULL;
John Thompson5ab4f112013-10-15 13:52:33 +0000223 }
224
225 return RootModule;
226}
227
228// Kick off the writing of the module map.
229static bool writeModuleMap(llvm::StringRef ModuleMapPath,
230 llvm::StringRef HeaderPrefix, Module *RootModule) {
231 llvm::SmallString<256> HeaderDirectory(ModuleMapPath);
232 llvm::sys::path::remove_filename(HeaderDirectory);
233 llvm::SmallString<256> FilePath;
234
235 // Get the module map file path to be used.
236 if ((HeaderDirectory.size() == 0) && (HeaderPrefix.size() != 0)) {
237 FilePath = HeaderPrefix;
238 // Prepend header file name prefix if it's not absolute.
239 llvm::sys::path::append(FilePath, ModuleMapPath);
240 llvm::sys::path::native(FilePath);
241 } else {
242 FilePath = ModuleMapPath;
243 llvm::sys::path::native(FilePath);
244 }
245
246 // Set up module map output file.
247 std::string Error;
248 llvm::tool_output_file Out(FilePath.c_str(), Error);
249 if (!Error.empty()) {
250 llvm::errs() << Argv0 << ": error opening " << FilePath << ":" << Error
251 << "\n";
252 return false;
253 }
254
255 // Get output stream from tool output buffer/manager.
256 llvm::raw_fd_ostream &OS = Out.os();
257
258 // Output file comment.
259 OS << "// " << ModuleMapPath << "\n";
260 OS << "// Generated by: " << CommandLine << "\n\n";
261
262 // Write module hierarchy from internal representation.
263 if (!RootModule->output(OS, 0))
264 return false;
265
266 // Tell tool_output_file that we want to keep the file.
267 Out.keep();
268
269 return true;
270}
271
272// Global functions:
273
274// Module map generation entry point.
275bool createModuleMap(llvm::StringRef ModuleMapPath,
276 llvm::ArrayRef<std::string> HeaderFileNames,
277 DependencyMap &Dependencies, llvm::StringRef HeaderPrefix,
278 llvm::StringRef RootModuleName) {
279 // Load internal representation of modules.
280 llvm::OwningPtr<Module> RootModule(loadModuleDescriptions(
281 RootModuleName, HeaderFileNames, Dependencies, HeaderPrefix));
282 if (!RootModule.get())
283 return false;
284
285 // Write module map file.
286 return writeModuleMap(ModuleMapPath, HeaderPrefix, RootModule.get());
287}