[cfe-commits] r144797 - in /cfe/trunk: include/clang/Basic/DiagnosticFrontendKinds.td lib/Frontend/FrontendActions.cpp test/Modules/normal-module-map.cpp

Douglas Gregor dgregor at apple.com
Wed Nov 16 09:04:00 PST 2011


Author: dgregor
Date: Wed Nov 16 11:04:00 2011
New Revision: 144797

URL: http://llvm.org/viewvc/llvm-project?rev=144797&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/test/Modules/normal-module-map.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=144797&r1=144796&r2=144797&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Wed Nov 16 11:04:00 2011
@@ -178,4 +178,6 @@
   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;
 }

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=144797&r1=144796&r2=144797&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Wed Nov 16 11:04:00 2011
@@ -126,6 +126,38 @@
                           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 @@
     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;
 }
 

Modified: cfe/trunk/test/Modules/normal-module-map.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/normal-module-map.cpp?rev=144797&r1=144796&r2=144797&view=diff
==============================================================================
--- cfe/trunk/test/Modules/normal-module-map.cpp (original)
+++ cfe/trunk/test/Modules/normal-module-map.cpp Wed Nov 16 11:04:00 2011
@@ -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() { 





More information about the cfe-commits mailing list