Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit db1cde7

Browse files
committed
Add support for building a module from a module map to the -cc1
interface. This is currently limited to modules with umbrella headers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144736 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent e614d6c commit db1cde7

12 files changed

+208
-7
lines changed

include/clang/Basic/DiagnosticFrontendKinds.td

+8
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,12 @@ def warn_incompatible_analyzer_plugin_api : Warning<
170170
InGroup<DiagGroup<"analyzer-incompatible-plugin"> >;
171171
def note_incompatible_analyzer_plugin_api : Note<
172172
"current API version is '%0', but plugin was compiled with version '%1'">;
173+
174+
def err_module_map_not_found : Error<"module map file '%0' not found">,
175+
DefaultFatal;
176+
def err_missing_module_name : Error<
177+
"no module name provided; specify one with -fmodule-name=">,
178+
DefaultFatal;
179+
def err_missing_module : Error<
180+
"no module named '%0' declared in module map file '%1'">, DefaultFatal;
173181
}

include/clang/Driver/CC1Options.td

+2
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ def print_decl_contexts : Flag<"-print-decl-contexts">,
377377
HelpText<"Print DeclContexts and their Decls">;
378378
def emit_module : Flag<"-emit-module">,
379379
HelpText<"Generate pre-compiled module file">;
380+
def emit_module_from_map : Flag<"-emit-module-from-map">,
381+
HelpText<"Generate pre-compiled module file from module map">;
380382
def emit_pth : Flag<"-emit-pth">,
381383
HelpText<"Generate pre-tokenized header file">;
382384
def emit_pch : Flag<"-emit-pch">,

include/clang/Frontend/FrontendActions.h

+25
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,31 @@ class GeneratePCHAction : public ASTFrontendAction {
9494
raw_ostream *&OS);
9595
};
9696

97+
class GenerateModuleAction : public ASTFrontendAction {
98+
protected:
99+
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
100+
StringRef InFile);
101+
102+
virtual TranslationUnitKind getTranslationUnitKind() {
103+
return TU_Module;
104+
}
105+
106+
virtual bool hasASTFileSupport() const { return false; }
107+
108+
public:
109+
virtual bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename);
110+
111+
/// \brief Compute the AST consumer arguments that will be used to
112+
/// create the PCHGenerator instance returned by CreateASTConsumer.
113+
///
114+
/// \returns true if an error occurred, false otherwise.
115+
static bool ComputeASTConsumerArguments(CompilerInstance &CI,
116+
StringRef InFile,
117+
std::string &Sysroot,
118+
std::string &OutputFile,
119+
raw_ostream *&OS);
120+
};
121+
97122
class SyntaxOnlyAction : public ASTFrontendAction {
98123
protected:
99124
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,

include/clang/Frontend/FrontendOptions.h

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ namespace frontend {
3535
EmitObj, ///< Emit a .o file.
3636
FixIt, ///< Parse and apply any fixits to the source.
3737
GenerateModule, ///< Generate pre-compiled module.
38+
GenerateModuleFromMap, ///< Generate pre-compiled module from module map.
3839
GeneratePCH, ///< Generate pre-compiled header.
3940
GeneratePTH, ///< Generate pre-tokenized header.
4041
InitOnly, ///< Only execute frontend initialization.

include/clang/Lex/HeaderSearch.h

+23
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ class HeaderSearch {
214214
this->BuildingModule = BuildingModule;
215215
}
216216

217+
/// \brief Retrieve the path to the module cache.
218+
StringRef getModuleCachePath() const { return ModuleCachePath; }
219+
217220
/// ClearFileInfo - Forget everything we know about headers so far.
218221
void ClearFileInfo() {
219222
FileInfo.clear();
@@ -367,6 +370,26 @@ class HeaderSearch {
367370
/// FIXME: This will need to be generalized for submodules.
368371
StringRef findModuleForHeader(const FileEntry *File);
369372

373+
374+
/// \brief Read the contents of the given module map file.
375+
///
376+
/// \param File The module map file.
377+
///
378+
/// \param OnlyModule If non-NULL, this will receive the
379+
///
380+
/// \returns true if an error occurred, false otherwise.
381+
bool loadModuleMapFile(const FileEntry *File);
382+
383+
/// \brief Retrieve a module with the given name.
384+
///
385+
/// \param Name The name of the module to retrieve.
386+
///
387+
/// \param AllowSearch If true, we're allowed to look for module maps within
388+
/// the header search path. Otherwise, the module must already be known.
389+
///
390+
/// \returns The module, if found; otherwise, null.
391+
ModuleMap::Module *getModule(StringRef Name, bool AllowSearch = true);
392+
370393
unsigned header_file_size() const { return FileInfo.size(); }
371394

372395
// Used by ASTReader.

lib/Frontend/CompilerInvocation.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
394394
case frontend::EmitObj: return "-emit-obj";
395395
case frontend::FixIt: return "-fixit";
396396
case frontend::GenerateModule: return "-emit-module";
397+
case frontend::GenerateModuleFromMap: return "-emit-module-from-map";
397398
case frontend::GeneratePCH: return "-emit-pch";
398399
case frontend::GeneratePTH: return "-emit-pth";
399400
case frontend::InitOnly: return "-init-only";
@@ -1252,6 +1253,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
12521253
Opts.ProgramAction = frontend::FixIt; break;
12531254
case OPT_emit_module:
12541255
Opts.ProgramAction = frontend::GenerateModule; break;
1256+
case OPT_emit_module_from_map:
1257+
Opts.ProgramAction = frontend::GenerateModuleFromMap; break;
12551258
case OPT_emit_pch:
12561259
Opts.ProgramAction = frontend::GeneratePCH; break;
12571260
case OPT_emit_pth:

lib/Frontend/FrontendActions.cpp

+93
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "clang/Frontend/FrontendActions.h"
1111
#include "clang/AST/ASTConsumer.h"
12+
#include "clang/Lex/HeaderSearch.h"
1213
#include "clang/Lex/Pragma.h"
1314
#include "clang/Lex/Preprocessor.h"
1415
#include "clang/Parse/Parser.h"
@@ -113,6 +114,98 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
113114
return false;
114115
}
115116

117+
ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
118+
StringRef InFile) {
119+
std::string Sysroot;
120+
std::string OutputFile;
121+
raw_ostream *OS = 0;
122+
if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS))
123+
return 0;
124+
125+
return new PCHGenerator(CI.getPreprocessor(), OutputFile, /*MakeModule=*/true,
126+
Sysroot, OS);
127+
}
128+
129+
bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
130+
StringRef Filename) {
131+
// Find the module map file.
132+
const FileEntry *ModuleMap = CI.getFileManager().getFile(Filename);
133+
if (!ModuleMap) {
134+
CI.getDiagnostics().Report(diag::err_module_map_not_found)
135+
<< Filename;
136+
return false;
137+
}
138+
139+
// Parse the module map file.
140+
HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
141+
if (HS.loadModuleMapFile(ModuleMap))
142+
return false;
143+
144+
if (CI.getLangOpts().CurrentModule.empty()) {
145+
CI.getDiagnostics().Report(diag::err_missing_module_name);
146+
147+
// FIXME: Eventually, we could consider asking whether there was just
148+
// a single module described in the module map, and use that as a
149+
// default. Then it would be fairly trivial to just "compile" a module
150+
// map with a single module (the common case).
151+
return false;
152+
}
153+
154+
// Dig out the module definition.
155+
ModuleMap::Module *Module = HS.getModule(CI.getLangOpts().CurrentModule,
156+
/*AllowSearch=*/false);
157+
if (!Module) {
158+
CI.getDiagnostics().Report(diag::err_missing_module)
159+
<< CI.getLangOpts().CurrentModule << Filename;
160+
161+
return false;
162+
}
163+
164+
// If there is an umbrella header, use it as our actual input file.
165+
if (Module->UmbrellaHeader) {
166+
// FIXME: Deal with explicit submodule headers, which won't be contained
167+
// within the umbrella header.
168+
fprintf(stderr, "note: using umbrella header \"%s\"\n",
169+
Module->UmbrellaHeader->getName());
170+
setCurrentFile(Module->UmbrellaHeader->getName(), getCurrentFileKind());
171+
} else {
172+
// FIXME: Deal with the non-umbrella case, where we have to synthesize
173+
// a header to parse.
174+
// FIXME: Diagnose, at least for now.
175+
return false;
176+
}
177+
178+
return true;
179+
}
180+
181+
bool GenerateModuleAction::ComputeASTConsumerArguments(CompilerInstance &CI,
182+
StringRef InFile,
183+
std::string &Sysroot,
184+
std::string &OutputFile,
185+
raw_ostream *&OS) {
186+
// If no output file was provided, figure out where this module would go
187+
// in the module cache.
188+
if (CI.getFrontendOpts().OutputFile.empty()) {
189+
HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
190+
llvm::SmallString<256> ModuleFileName(HS.getModuleCachePath());
191+
llvm::sys::path::append(ModuleFileName,
192+
CI.getLangOpts().CurrentModule + ".pcm");
193+
CI.getFrontendOpts().OutputFile = ModuleFileName.str();
194+
}
195+
196+
// We use createOutputFile here because this is exposed via libclang, and we
197+
// must disable the RemoveFileOnSignal behavior.
198+
// We use a temporary to avoid race conditions.
199+
OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
200+
/*RemoveFileOnSignal=*/false, InFile,
201+
/*Extension=*/"", /*useTemporary=*/true);
202+
if (!OS)
203+
return true;
204+
205+
OutputFile = CI.getFrontendOpts().OutputFile;
206+
return false;
207+
}
208+
116209
ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
117210
StringRef InFile) {
118211
return new ASTConsumer();

lib/FrontendTool/ExecuteCompilerInvocation.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
5050
case EmitObj: return new EmitObjAction();
5151
case FixIt: return new FixItAction();
5252
case GenerateModule: return new GeneratePCHAction(true);
53+
case GenerateModuleFromMap: return new GenerateModuleAction;
5354
case GeneratePCH: return new GeneratePCHAction(false);
5455
case GeneratePTH: return new GeneratePTHAction();
5556
case InitOnly: return new InitOnlyAction();

lib/Lex/HeaderSearch.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,46 @@ StringRef HeaderSearch::findModuleForHeader(const FileEntry *File) {
800800
return StringRef();
801801
}
802802

803+
bool HeaderSearch::loadModuleMapFile(const FileEntry *File) {
804+
const DirectoryEntry *Dir = File->getDir();
805+
806+
llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
807+
= DirectoryHasModuleMap.find(Dir);
808+
if (KnownDir != DirectoryHasModuleMap.end())
809+
return !KnownDir->second;
810+
811+
bool Result = ModMap.parseModuleMapFile(File);
812+
DirectoryHasModuleMap[Dir] = !Result;
813+
return Result;
814+
}
815+
816+
ModuleMap::Module *HeaderSearch::getModule(StringRef Name, bool AllowSearch) {
817+
if (ModuleMap::Module *Module = ModMap.findModule(Name))
818+
return Module;
819+
820+
if (!AllowSearch)
821+
return 0;
822+
823+
for (unsigned I = 0, N = SearchDirs.size(); I != N; ++I) {
824+
if (!SearchDirs[I].isNormalDir())
825+
continue;
826+
827+
switch (loadModuleMapFile(SearchDirs[I].getDir())) {
828+
case LMM_AlreadyLoaded:
829+
case LMM_InvalidModuleMap:
830+
case LMM_NoDirectory:
831+
break;
832+
833+
case LMM_NewlyLoaded:
834+
if (ModuleMap::Module *Module = ModMap.findModule(Name))
835+
return Module;
836+
break;
837+
}
838+
}
839+
840+
return 0;
841+
}
842+
803843
HeaderSearch::LoadModuleMapResult
804844
HeaderSearch::loadModuleMapFile(StringRef DirName) {
805845
if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))

test/Modules/Inputs/module.map

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module diamond_top { umbrella "diamond_top.h" }
2+
module diamond_left { umbrella "diamond_left.h" }
3+
module diamond_right { umbrella "diamond_right.h" }
4+
module diamond_bottom { umbrella "diamond_bottom.h" }

test/Modules/diamond.c

+6-5
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ void test_diamond(int i, float f, double d, char c) {
2020
lr.left = 17;
2121
}
2222

23-
// RUN: %clang_cc1 -emit-module -o %T/diamond_top.pcm %S/Inputs/diamond_top.h
24-
// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_left.pcm %S/Inputs/diamond_left.h
25-
// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_right.pcm %S/Inputs/diamond_right.h
26-
// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_bottom.pcm %S/Inputs/diamond_bottom.h
27-
// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash %s -verify
23+
// RUN: rm -rf %t
24+
// RUN: %clang_cc1 -emit-module-from-map -fmodule-cache-path %t -fmodule-name=diamond_top %S/Inputs/module.map
25+
// RUN: %clang_cc1 -emit-module-from-map -fmodule-cache-path %t -fmodule-name=diamond_left %S/Inputs/module.map
26+
// RUN: %clang_cc1 -emit-module-from-map -fmodule-cache-path %t -fmodule-name=diamond_right %S/Inputs/module.map
27+
// RUN: %clang_cc1 -emit-module-from-map -fmodule-cache-path %t -fmodule-name=diamond_bottom %S/Inputs/module.map
28+
// RUN: %clang_cc1 -fmodule-cache-path %t %s -verify

test/Modules/normal-module-map.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// RUN: rm -rf %t
22
// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/normal-module-map %s -verify
33

4-
// FIXME: The expected error here is temporary, since we don't yet have the
5-
// logic to build a module from a module map.
64
#include "Umbrella/Umbrella.h"
75

86
int getUmbrella() {
@@ -11,6 +9,8 @@ int getUmbrella() {
119

1210
__import_module__ Umbrella2;
1311

12+
// FIXME: The expected error here is temporary, since we don't yet have the
13+
// logic to build a module from a module map.
1414
#include "a1.h" // expected-error{{module 'libA' not found}}
1515
#include "b1.h"
1616
#include "nested/nested2.h"

0 commit comments

Comments
 (0)