When building a module from a module map that isn't simply an umbrella

header, create our own in-memory buffer to parse all of the
appropriate headers, and use that to build the module. This isn't
end-to-end testable yet; that's coming next.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144797 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2011-11-16 17:04:00 +00:00
Родитель 30bb420cfe
Коммит 261e75bd10
3 изменённых файлов: 97 добавлений и 10 удалений

Просмотреть файл

@ -178,4 +178,6 @@ def err_missing_module_name : Error<
DefaultFatal;
def err_missing_module : Error<
"no module named '%0' declared in module map file '%1'">, DefaultFatal;
def err_missing_umbrella_header : Error<
"cannot open umbrella header '%0': %1">, DefaultFatal;
}

Просмотреть файл

@ -126,6 +126,38 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
Sysroot, OS);
}
/// \brief Collect the set of header includes needed to construct the given
/// module.
///
/// \param Module The module we're collecting includes from.
/// \param ExplicitOnly Whether we should only add headers from explicit
static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
ModuleMap::Module *Module,
bool ExplicitOnly,
llvm::SmallString<256> &Includes) {
if (!ExplicitOnly || Module->IsExplicit) {
// Add includes for each of these headers.
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
if (LangOpts.ObjC1)
Includes += "#import \"";
else
Includes += "#include \"";
Includes += Module->Headers[I]->getName();
Includes += "\"\n";
}
}
// Recurse into submodules.
for (llvm::StringMap<ModuleMap::Module *>::iterator
Sub = Module->SubModules.begin(),
SubEnd = Module->SubModules.end();
Sub != SubEnd; ++Sub) {
collectModuleHeaderIncludes(LangOpts, Sub->getValue(),
ExplicitOnly && !Module->IsExplicit,
Includes);
}
}
bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
StringRef Filename) {
// Find the module map file.
@ -161,18 +193,72 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
return false;
}
// If there is an umbrella header, use it as our actual input file.
if (Module->UmbrellaHeader) {
// FIXME: Deal with explicit submodule headers, which won't be contained
// within the umbrella header.
// Collect the set of #includes we need to build the module.
llvm::SmallString<256> HeaderContents;
collectModuleHeaderIncludes(CI.getLangOpts(), Module,
Module->UmbrellaHeader != 0, HeaderContents);
if (Module->UmbrellaHeader && HeaderContents.empty()) {
// Simple case: we have an umbrella header and there are no additional
// includes, we can just parse the umbrella header directly.
setCurrentFile(Module->UmbrellaHeader->getName(), getCurrentFileKind());
} else {
// FIXME: Deal with the non-umbrella case, where we have to synthesize
// a header to parse.
// FIXME: Diagnose, at least for now.
return false;
return true;
}
FileManager &FileMgr = CI.getFileManager();
llvm::SmallString<128> HeaderName;
time_t ModTime;
if (Module->UmbrellaHeader) {
// Read in the umbrella header.
// FIXME: Go through the source manager; the umbrella header may have
// been overridden.
std::string ErrorStr;
llvm::MemoryBuffer *UmbrellaContents
= FileMgr.getBufferForFile(Module->UmbrellaHeader, &ErrorStr);
if (!UmbrellaContents) {
CI.getDiagnostics().Report(diag::err_missing_umbrella_header)
<< Module->UmbrellaHeader->getName() << ErrorStr;
return false;
}
// Combine the contents of the umbrella header with the automatically-
// generated includes.
llvm::SmallString<256> OldContents = HeaderContents;
HeaderContents = UmbrellaContents->getBuffer();
HeaderContents += "\n\n";
HeaderContents += "/* Module includes */\n";
HeaderContents += OldContents;
// Pretend that we're parsing the umbrella header.
HeaderName = Module->UmbrellaHeader->getName();
ModTime = Module->UmbrellaHeader->getModificationTime();
delete UmbrellaContents;
} else {
// Pick an innocuous-sounding name for the umbrella header.
HeaderName = Module->Name + ".h";
if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
/*CacheFailure=*/false)) {
// Try again!
HeaderName = Module->Name + "-module.h";
if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
/*CacheFailure=*/false)) {
// Pick something ridiculous and go with it.
HeaderName = Module->Name + "-module.hmod";
}
}
ModTime = time(0);
}
// Remap the contents of the header name we're using to our synthesized
// buffer.
const FileEntry *HeaderFile = FileMgr.getVirtualFile(HeaderName,
HeaderContents.size(),
ModTime);
llvm::MemoryBuffer *HeaderContentsBuf
= llvm::MemoryBuffer::getMemBufferCopy(HeaderContents);
CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf);
setCurrentFile(HeaderName, getCurrentFileKind());
return true;
}

Просмотреть файл

@ -1,6 +1,5 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/normal-module-map %s -verify
#include "Umbrella/Umbrella.h"
int getUmbrella() {