From: Douglas Gregor Date: Tue, 29 Nov 2011 19:06:37 +0000 (+0000) Subject: Teach the module import mechanism how to rebuild modules expressed via X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f9e357d8a66c606a86a6e1aef678898b8843bd30;p=clang Teach the module import mechanism how to rebuild modules expressed via module map, rather than assuming that there is an umbrella header. This allows us to automatically build umbrella-less modules. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145415 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index d38bbe672b..4f89f1e728 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -166,7 +166,16 @@ public: /// framework directory. Module *inferFrameworkModule(StringRef ModuleName, const DirectoryEntry *FrameworkDir); - + + /// \brief Retrieve the module map file containing the definition of the given + /// module. + /// + /// \param Module The module whose module map file will be returned, if known. + /// + /// \returns The file entry for the module map file containing the given + /// module, or NULL if the module definition was inferred. + const FileEntry *getContainingModuleMapFile(ModuleMap::Module *Module); + /// \brief Parse the given module map file, and record any modules we /// encounter. /// diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index c6a5583984..433b2cceb7 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -709,6 +709,21 @@ static void doCompileModule(void *UserData) { Data.Instance.ExecuteAction(Data.CreateModuleAction); } +namespace { + struct CompileModuleMapData { + CompilerInstance &Instance; + GenerateModuleAction &CreateModuleAction; + }; +} + +/// \brief Helper function that executes the module-generating action under +/// a crash recovery context. +static void doCompileMapModule(void *UserData) { + CompileModuleMapData &Data + = *reinterpret_cast(UserData); + Data.Instance.ExecuteAction(Data.CreateModuleAction); +} + namespace { /// \brief Class that manages the creation of a lock file to aid /// implicit coordination between different processes. @@ -958,17 +973,11 @@ void LockFileManager::waitForUnlock() { // Give up. } -/// \brief Compile a module file for the given module name with the given -/// umbrella header, using the options provided by the importing compiler -/// instance. +/// \brief Compile a module file for the given module, using the options +/// provided by the importing compiler instance. static void compileModule(CompilerInstance &ImportingInstance, ModuleMap::Module *Module, StringRef ModuleFileName) { - // FIXME: Currently, we can only handle modules that have an umbrella - // header. That's lame. - if (!Module->UmbrellaHeader) - return; - LockFileManager Locked(ModuleFileName); switch (Locked) { case LockFileManager::LFS_Error: @@ -985,6 +994,9 @@ static void compileModule(CompilerInstance &ImportingInstance, break; } + ModuleMap &ModMap + = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + // Construct a compiler invocation for creating this module. llvm::IntrusiveRefCntPtr Invocation (new CompilerInvocation(ImportingInstance.getInvocation())); @@ -1002,6 +1014,50 @@ static void compileModule(CompilerInstance &ImportingInstance, Invocation->getPreprocessorOpts().ModuleBuildPath .push_back(Module->getTopLevelModuleName()); + if (const FileEntry *ModuleMapFile + = ModMap.getContainingModuleMapFile(Module)) { + // If there is a module map file, build the module using the module map. + // Set up the inputs/outputs so that we build the module from its umbrella + // header. + FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); + FrontendOpts.OutputFile = ModuleFileName.str(); + FrontendOpts.DisableFree = false; + FrontendOpts.Inputs.clear(); + FrontendOpts.Inputs.push_back( + std::make_pair(getSourceInputKindFromOptions(*Invocation->getLangOpts()), + ModuleMapFile->getName())); + + Invocation->getDiagnosticOpts().VerifyDiagnostics = 0; + + + assert(ImportingInstance.getInvocation().getModuleHash() == + Invocation->getModuleHash() && "Module hash mismatch!"); + + // Construct a compiler instance that will be used to actually create the + // module. + CompilerInstance Instance; + Instance.setInvocation(&*Invocation); + Instance.createDiagnostics(/*argc=*/0, /*argv=*/0, + &ImportingInstance.getDiagnosticClient(), + /*ShouldOwnClient=*/true, + /*ShouldCloneClient=*/true); + + // Construct a module-generating action. + GenerateModuleAction CreateModuleAction; + + // Execute the action to actually build the module in-place. Use a separate + // thread so that we get a stack large enough. + const unsigned ThreadStackSize = 8 << 20; + llvm::CrashRecoveryContext CRC; + CompileModuleMapData Data = { Instance, CreateModuleAction }; + CRC.RunSafelyOnThread(&doCompileMapModule, &Data, ThreadStackSize); + return; + } + + // FIXME: Temporary fallback: generate the module from the umbrella header. + // This is currently used when we infer a module map from a framework. + assert(Module->UmbrellaHeader && "Inferred module map needs umbrella header"); + // Set up the inputs/outputs so that we build the module from its umbrella // header. FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index a25c93bfca..3cc6478acf 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -206,6 +206,15 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, return Result; } +const FileEntry * +ModuleMap::getContainingModuleMapFile(ModuleMap::Module *Module) { + if (Module->DefinitionLoc.isInvalid() || !SourceMgr) + return 0; + + return SourceMgr->getFileEntryForID( + SourceMgr->getFileID(Module->DefinitionLoc)); +} + void ModuleMap::dump() { llvm::errs() << "Modules:"; for (llvm::StringMap::iterator M = Modules.begin(), diff --git a/test/Modules/normal-module-map.cpp b/test/Modules/normal-module-map.cpp index c87657f5a9..19294950d4 100644 --- a/test/Modules/normal-module-map.cpp +++ b/test/Modules/normal-module-map.cpp @@ -1,8 +1,4 @@ // RUN: rm -rf %t -// FIXME: Eventually, we should be able to remove these explicit module creation lines -// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fmodule-name=libA -emit-module-from-map %S/Inputs/normal-module-map/module.map -// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fmodule-name=libB -emit-module-from-map %S/Inputs/normal-module-map/module.map -// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fmodule-name=libNested -emit-module-from-map %S/Inputs/normal-module-map/nested/module.map // RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/normal-module-map %s -verify #include "Umbrella/umbrella_sub.h"