]> granicus.if.org Git - clang/commitdiff
Teach the module import mechanism how to rebuild modules expressed via
authorDouglas Gregor <dgregor@apple.com>
Tue, 29 Nov 2011 19:06:37 +0000 (19:06 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 29 Nov 2011 19:06:37 +0000 (19:06 +0000)
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

include/clang/Lex/ModuleMap.h
lib/Frontend/CompilerInstance.cpp
lib/Lex/ModuleMap.cpp
test/Modules/normal-module-map.cpp

index d38bbe672bd8e83f68bbba86bf58ae466f3a17b7..4f89f1e72888a400c274546d01aa7b554a43aacc 100644 (file)
@@ -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.
   ///
index c6a55839848d0163c5e88749edbe016571eaa6a1..433b2cceb7d219676fe7353478ceed20f36f8de1 100644 (file)
@@ -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<CompileModuleMapData *>(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<CompilerInvocation> 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();
index a25c93bfca4afd8f7d31099da7fbc5c583c9fb84..3cc6478acf6b0de1e4980ef8bd1ddcef3c71780d 100644 (file)
@@ -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<Module *>::iterator M = Modules.begin(), 
index c87657f5a9ba32b3f3ff10e754da5722e13fec0f..19294950d49dbf032020c3df14ba7a79ecbdb9cd 100644 (file)
@@ -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"