[cfe-commits] r139558 - in /cfe/trunk: include/clang/Basic/DiagnosticCommonKinds.td include/clang/Basic/FileManager.h include/clang/Lex/HeaderSearch.h lib/Basic/FileManager.cpp lib/Frontend/CompilerInstance.cpp lib/Lex/HeaderSearch.cpp test/Modules/Inputs/Module.framework/ test/Modules/Inputs/Module.framework/Headers/ test/Modules/Inputs/Module.framework/Headers/Module.h test/Modules/on-demand-build.m

Douglas Gregor dgregor at apple.com
Mon Sep 12 16:31:24 PDT 2011


Author: dgregor
Date: Mon Sep 12 18:31:24 2011
New Revision: 139558

URL: http://llvm.org/viewvc/llvm-project?rev=139558&view=rev
Log:
When an import statement fails to find a module in the module cache,
but there is a corresponding umbrella header in a framework, build the
module on-the-fly so it can be immediately loaded at the import
statement. This is very much proof-of-concept code, with details to be
fleshed out over time.

Added:
    cfe/trunk/test/Modules/Inputs/Module.framework/
    cfe/trunk/test/Modules/Inputs/Module.framework/Headers/
    cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h
    cfe/trunk/test/Modules/on-demand-build.m
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
    cfe/trunk/include/clang/Basic/FileManager.h
    cfe/trunk/include/clang/Lex/HeaderSearch.h
    cfe/trunk/lib/Basic/FileManager.cpp
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Lex/HeaderSearch.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td?rev=139558&r1=139557&r2=139558&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td Mon Sep 12 18:31:24 2011
@@ -60,6 +60,7 @@
 def err_deleted_non_function : Error<
   "only functions can have deleted definitions">;
 def err_module_not_found : Error<"module '%0' not found">, DefaultFatal;
+def err_module_not_built : Error<"could not build module '%0'">, DefaultFatal;
   
 // Sema && Lex
 def ext_longlong : Extension<

Modified: cfe/trunk/include/clang/Basic/FileManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/FileManager.h?rev=139558&r1=139557&r2=139558&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/FileManager.h (original)
+++ cfe/trunk/include/clang/Basic/FileManager.h Mon Sep 12 18:31:24 2011
@@ -187,6 +187,10 @@
   /// \param openFile if true and the file exists, it will be opened.
   const FileEntry *getFile(StringRef Filename, bool openFile = false);
 
+  /// \brief Forget any information about the given file name, because (for 
+  /// example) something within this process has changed the file in some way.
+  void forgetFile(StringRef Filename);
+  
   /// \brief Returns the current file system options
   const FileSystemOptions &getFileSystemOptions() { return FileSystemOpts; }
 

Modified: cfe/trunk/include/clang/Lex/HeaderSearch.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/HeaderSearch.h?rev=139558&r1=139557&r2=139558&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/HeaderSearch.h (original)
+++ cfe/trunk/include/clang/Lex/HeaderSearch.h Mon Sep 12 18:31:24 2011
@@ -319,9 +319,15 @@
   /// \brief Search in the module cache path for a module with the given
   /// name.
   ///
+  /// \param UmbrellaHeader If non-NULL, and no module was found in the module
+  /// cache, this routine will search in the framework paths to determine
+  /// whether a module can be built from an umbrella header. If so, the pointee
+  /// will be set to the path of the umbrella header.
+  ///
   /// \returns A file describing the named module, if available, or NULL to
   /// indicate that the module could not be found.
-  const FileEntry *lookupModule(StringRef ModuleName);
+  const FileEntry *lookupModule(StringRef ModuleName,
+                                std::string *UmbrellaHeader = 0);
   
   void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
 

Modified: cfe/trunk/lib/Basic/FileManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=139558&r1=139557&r2=139558&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/FileManager.cpp (original)
+++ cfe/trunk/lib/Basic/FileManager.cpp Mon Sep 12 18:31:24 2011
@@ -380,6 +380,10 @@
   return &UFE;
 }
 
+void FileManager::forgetFile(StringRef Filename) {
+  SeenFileEntries.erase(Filename);
+}
+
 const FileEntry *
 FileManager::getVirtualFile(StringRef Filename, off_t Size,
                             time_t ModificationTime) {

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=139558&r1=139557&r2=139558&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Mon Sep 12 18:31:24 2011
@@ -21,6 +21,7 @@
 #include "clang/Lex/PTHManager.h"
 #include "clang/Frontend/ChainedDiagnosticClient.h"
 #include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendActions.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/LogDiagnosticPrinter.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -624,6 +625,64 @@
   return !getDiagnostics().getClient()->getNumErrors();
 }
 
+/// \brief Determine the appropriate source input kind based on language
+/// options.
+static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) {
+  if (LangOpts.OpenCL)
+    return IK_OpenCL;
+  if (LangOpts.CUDA)
+    return IK_CUDA;
+  if (LangOpts.ObjC1)
+    return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC;
+  return LangOpts.CPlusPlus? IK_CXX : IK_C;
+}
+
+/// \brief Compile a module file for the given module name with the given
+/// umbrella header, using the options provided by the importing compiler
+/// instance.
+static void compileModule(CompilerInstance &ImportingInstance,
+                          StringRef ModuleName,
+                          StringRef UmbrellaHeader) {
+  // Determine the file that we'll be writing to.
+  llvm::SmallString<128> ModuleFile;
+  ModuleFile += 
+    ImportingInstance.getInvocation().getHeaderSearchOpts().ModuleCachePath;
+  llvm::sys::path::append(ModuleFile, ModuleName + ".pcm");
+  
+  // Construct a compiler invocation for creating this module.
+  llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation
+    (new CompilerInvocation(ImportingInstance.getInvocation()));
+  FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
+  FrontendOpts.OutputFile = ModuleFile.str();
+  FrontendOpts.DisableFree = false;
+  FrontendOpts.Inputs.clear();
+  FrontendOpts.Inputs.push_back(
+    std::make_pair(getSourceInputKindFromOptions(Invocation->getLangOpts()), 
+                                                 UmbrellaHeader));
+  // FIXME: Strip away all of the compilation options that won't be transferred
+  // down to the module. This presumably includes -D flags, optimization 
+  // settings, etc.
+  
+  // Construct a compiler instance that will be used to actually create the
+  // module.
+  CompilerInstance Instance;
+  Instance.setInvocation(&*Invocation);
+  //  Instance.setDiagnostics(&ImportingInstance.getDiagnostics());
+  // FIXME: Need to route diagnostics over to the same diagnostic client!
+  Instance.createDiagnostics(0, 0, 0);
+
+  // Construct a module-generating action.
+  GeneratePCHAction CreateModuleAction(true);
+  
+  // Execute the action to actually build the module in-place.
+  // FIXME: Need to synchronize when multiple processes do this.
+  Instance.ExecuteAction(CreateModuleAction);
+  
+  // Tell the importing instance's file manager to forget about the module
+  // file, since we've just created it.
+  ImportingInstance.getFileManager().forgetFile(ModuleFile);
+}
+
 ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc, 
                                        IdentifierInfo &ModuleName,
                                        SourceLocation ModuleNameLoc) {  
@@ -636,10 +695,25 @@
     CurFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
 
   // Search for a module with the given name.
+  std::string UmbrellaHeader;
   const FileEntry *ModuleFile
-    = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName());
+    = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName(),
+                                             &UmbrellaHeader);
+  
+  bool BuildingModule = false;
+  if (!ModuleFile && !UmbrellaHeader.empty()) {
+    // We didn't find the module, but there is an umbrella header that
+    // can be used to create the module file. Create a separate compilation
+    // module to do so.
+    BuildingModule = true;
+    compileModule(*this, ModuleName.getName(), UmbrellaHeader);
+    ModuleFile = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName());
+  }
+  
   if (!ModuleFile) {
-    getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
+    getDiagnostics().Report(ModuleNameLoc, 
+                            BuildingModule? diag::err_module_not_built
+                                          : diag::err_module_not_found)
       << ModuleName.getName()
       << SourceRange(ImportLoc, ModuleNameLoc);
     return 0;

Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=139558&r1=139557&r2=139558&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Mon Sep 12 18:31:24 2011
@@ -98,14 +98,48 @@
   return 0;
 }
 
-const FileEntry *HeaderSearch::lookupModule(StringRef ModuleName) {
+const FileEntry *HeaderSearch::lookupModule(StringRef ModuleName,
+                                            std::string *UmbrellaHeader) {
   // If we don't have a module cache path, we can't do anything.
   if (ModuleCachePath.empty())
     return 0;
-  
+
+  // Try to find the module path.
   llvm::SmallString<256> FileName(ModuleCachePath);
   llvm::sys::path::append(FileName, ModuleName + ".pcm");
-  return getFileMgr().getFile(FileName);
+  if (const FileEntry *ModuleFile = getFileMgr().getFile(FileName))
+    return ModuleFile;
+  
+  // We didn't find the module. If we're not supposed to look for an
+  // umbrella header, this is the end of the road.
+  if (!UmbrellaHeader)
+    return 0;
+  
+  // Look in each of the framework directories for an umbrella header with
+  // the same name as the module.
+  // FIXME: We need a way for non-frameworks to provide umbrella headers.
+  llvm::SmallString<128> UmbrellaHeaderName;
+  UmbrellaHeaderName = ModuleName;
+  UmbrellaHeaderName += '/';
+  UmbrellaHeaderName += ModuleName;
+  UmbrellaHeaderName += ".h";
+  for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
+    // Skip non-framework include paths
+    if (!SearchDirs[Idx].isFramework())
+      continue;
+    
+    // Look for the umbrella header in this directory.
+    if (const FileEntry *HeaderFile
+          = SearchDirs[Idx].LookupFile(UmbrellaHeaderName, *this, 0, 0)) {
+      *UmbrellaHeader = HeaderFile->getName();
+      return 0;
+    }
+  }
+  
+  // We did not find an umbrella header. Clear out the UmbrellaHeader pointee
+  // so our caller knows that we failed.
+  UmbrellaHeader->clear();
+  return 0;
 }
 
 //===----------------------------------------------------------------------===//

Added: cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h?rev=139558&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h (added)
+++ cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h Mon Sep 12 18:31:24 2011
@@ -0,0 +1,6 @@
+const char *getModuleVersion(void);
+
+ at interface Module
++(const char *)version;
+ at end
+

Added: cfe/trunk/test/Modules/on-demand-build.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/on-demand-build.m?rev=139558&view=auto
==============================================================================
--- cfe/trunk/test/Modules/on-demand-build.m (added)
+++ cfe/trunk/test/Modules/on-demand-build.m Mon Sep 12 18:31:24 2011
@@ -0,0 +1,11 @@
+// RUN: mkdir -p %t
+// RUN: rm -f %t/Module.pcm
+// RUN: %clang_cc1 -fmodule-cache-path %t -F %S/Inputs -verify %s
+
+__import_module__ Module;
+void test_getModuleVersion() {
+  int version = getModuleVersion(); // expected-warning{{incompatible pointer to integer conversion initializing 'int' with an expression of type 'const char *'}}
+  int version2 = [Module version]; // expected-warning{{incompatible pointer to integer conversion initializing 'int' with an expression of type 'const char *'}}
+}
+
+





More information about the cfe-commits mailing list