[cfe-commits] r144736 - in /cfe/trunk: include/clang/Basic/DiagnosticFrontendKinds.td include/clang/Driver/CC1Options.td include/clang/Frontend/FrontendActions.h include/clang/Frontend/FrontendOptions.h include/clang/Lex/HeaderSearch.h lib/Frontend/CompilerInvocation.cpp lib/Frontend/FrontendActions.cpp lib/FrontendTool/ExecuteCompilerInvocation.cpp lib/Lex/HeaderSearch.cpp test/Modules/Inputs/module.map test/Modules/diamond.c test/Modules/normal-module-map.cpp

Douglas Gregor dgregor at apple.com
Tue Nov 15 16:09:07 PST 2011


Author: dgregor
Date: Tue Nov 15 18:09:06 2011
New Revision: 144736

URL: http://llvm.org/viewvc/llvm-project?rev=144736&view=rev
Log:
Add support for building a module from a module map to the -cc1
interface. This is currently limited to modules with umbrella
headers.

Added:
    cfe/trunk/test/Modules/Inputs/module.map
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Frontend/FrontendActions.h
    cfe/trunk/include/clang/Frontend/FrontendOptions.h
    cfe/trunk/include/clang/Lex/HeaderSearch.h
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp
    cfe/trunk/lib/Lex/HeaderSearch.cpp
    cfe/trunk/test/Modules/diamond.c
    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=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Tue Nov 15 18:09:06 2011
@@ -170,4 +170,12 @@
     InGroup<DiagGroup<"analyzer-incompatible-plugin"> >;
 def note_incompatible_analyzer_plugin_api : Note<
     "current API version is '%0', but plugin was compiled with version '%1'">;
+    
+def err_module_map_not_found : Error<"module map file '%0' not found">, 
+  DefaultFatal;
+def err_missing_module_name : Error<
+  "no module name provided; specify one with -fmodule-name=">, 
+  DefaultFatal;
+def err_missing_module : Error<
+  "no module named '%0' declared in module map file '%1'">, DefaultFatal;
 }

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Tue Nov 15 18:09:06 2011
@@ -377,6 +377,8 @@
   HelpText<"Print DeclContexts and their Decls">;
 def emit_module : Flag<"-emit-module">,
   HelpText<"Generate pre-compiled module file">;
+def emit_module_from_map : Flag<"-emit-module-from-map">,
+  HelpText<"Generate pre-compiled module file from module map">;
 def emit_pth : Flag<"-emit-pth">,
   HelpText<"Generate pre-tokenized header file">;
 def emit_pch : Flag<"-emit-pch">,

Modified: cfe/trunk/include/clang/Frontend/FrontendActions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendActions.h?rev=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendActions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendActions.h Tue Nov 15 18:09:06 2011
@@ -94,6 +94,31 @@
                                           raw_ostream *&OS);
 };
 
+class GenerateModuleAction : public ASTFrontendAction {
+protected:
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         StringRef InFile);
+  
+  virtual TranslationUnitKind getTranslationUnitKind() { 
+    return TU_Module;
+  }
+  
+  virtual bool hasASTFileSupport() const { return false; }
+  
+public:
+  virtual bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename);
+  
+  /// \brief Compute the AST consumer arguments that will be used to
+  /// create the PCHGenerator instance returned by CreateASTConsumer.
+  ///
+  /// \returns true if an error occurred, false otherwise.
+  static bool ComputeASTConsumerArguments(CompilerInstance &CI,
+                                          StringRef InFile,
+                                          std::string &Sysroot,
+                                          std::string &OutputFile,
+                                          raw_ostream *&OS);
+};
+  
 class SyntaxOnlyAction : public ASTFrontendAction {
 protected:
   virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,

Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Tue Nov 15 18:09:06 2011
@@ -35,6 +35,7 @@
     EmitObj,                ///< Emit a .o file.
     FixIt,                  ///< Parse and apply any fixits to the source.
     GenerateModule,         ///< Generate pre-compiled module.
+    GenerateModuleFromMap,  ///< Generate pre-compiled module from module map.
     GeneratePCH,            ///< Generate pre-compiled header.
     GeneratePTH,            ///< Generate pre-tokenized header.
     InitOnly,               ///< Only execute frontend initialization.

Modified: cfe/trunk/include/clang/Lex/HeaderSearch.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/HeaderSearch.h?rev=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/HeaderSearch.h (original)
+++ cfe/trunk/include/clang/Lex/HeaderSearch.h Tue Nov 15 18:09:06 2011
@@ -214,6 +214,9 @@
     this->BuildingModule = BuildingModule;
   }
   
+  /// \brief Retrieve the path to the module cache.
+  StringRef getModuleCachePath() const { return ModuleCachePath; }
+  
   /// ClearFileInfo - Forget everything we know about headers so far.
   void ClearFileInfo() {
     FileInfo.clear();
@@ -367,6 +370,26 @@
   /// FIXME: This will need to be generalized for submodules.
   StringRef findModuleForHeader(const FileEntry *File);
   
+  
+  /// \brief Read the contents of the given module map file.
+  ///
+  /// \param File The module map file.
+  ///
+  /// \param OnlyModule If non-NULL, this will receive the 
+  ///
+  /// \returns true if an error occurred, false otherwise.
+  bool loadModuleMapFile(const FileEntry *File);
+  
+  /// \brief Retrieve a module with the given name.
+  ///
+  /// \param Name The name of the module to retrieve.
+  ///
+  /// \param AllowSearch If true, we're allowed to look for module maps within
+  /// the header search path. Otherwise, the module must already be known.
+  ///
+  /// \returns The module, if found; otherwise, null.
+  ModuleMap::Module *getModule(StringRef Name, bool AllowSearch = true);
+  
   unsigned header_file_size() const { return FileInfo.size(); }
 
   // Used by ASTReader.

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Nov 15 18:09:06 2011
@@ -394,6 +394,7 @@
   case frontend::EmitObj:                return "-emit-obj";
   case frontend::FixIt:                  return "-fixit";
   case frontend::GenerateModule:         return "-emit-module";
+  case frontend::GenerateModuleFromMap:  return "-emit-module-from-map";
   case frontend::GeneratePCH:            return "-emit-pch";
   case frontend::GeneratePTH:            return "-emit-pth";
   case frontend::InitOnly:               return "-init-only";
@@ -1252,6 +1253,8 @@
       Opts.ProgramAction = frontend::FixIt; break;
     case OPT_emit_module:
       Opts.ProgramAction = frontend::GenerateModule; break;
+    case OPT_emit_module_from_map:
+      Opts.ProgramAction = frontend::GenerateModuleFromMap; break;
     case OPT_emit_pch:
       Opts.ProgramAction = frontend::GeneratePCH; break;
     case OPT_emit_pth:

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Tue Nov 15 18:09:06 2011
@@ -9,6 +9,7 @@
 
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/Pragma.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Parse/Parser.h"
@@ -113,6 +114,98 @@
   return false;
 }
 
+ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
+                                                     StringRef InFile) {
+  std::string Sysroot;
+  std::string OutputFile;
+  raw_ostream *OS = 0;
+  if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS))
+    return 0;
+  
+  return new PCHGenerator(CI.getPreprocessor(), OutputFile, /*MakeModule=*/true, 
+                          Sysroot, OS);
+}
+
+bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, 
+                                                 StringRef Filename) {
+  // Find the module map file.  
+  const FileEntry *ModuleMap = CI.getFileManager().getFile(Filename);
+  if (!ModuleMap)  {
+    CI.getDiagnostics().Report(diag::err_module_map_not_found)
+      << Filename;
+    return false;
+  }
+  
+  // Parse the module map file.
+  HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+  if (HS.loadModuleMapFile(ModuleMap))
+    return false;
+  
+  if (CI.getLangOpts().CurrentModule.empty()) {
+    CI.getDiagnostics().Report(diag::err_missing_module_name);
+    
+    // FIXME: Eventually, we could consider asking whether there was just
+    // a single module described in the module map, and use that as a 
+    // default. Then it would be fairly trivial to just "compile" a module
+    // map with a single module (the common case).
+    return false;
+  }
+  
+  // Dig out the module definition.
+  ModuleMap::Module *Module = HS.getModule(CI.getLangOpts().CurrentModule,
+                                           /*AllowSearch=*/false);
+  if (!Module) {
+    CI.getDiagnostics().Report(diag::err_missing_module)
+      << CI.getLangOpts().CurrentModule << Filename;
+    
+    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.
+    fprintf(stderr, "note: using umbrella header \"%s\"\n", 
+            Module->UmbrellaHeader->getName());
+    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;
+}
+
+bool GenerateModuleAction::ComputeASTConsumerArguments(CompilerInstance &CI,
+                                                       StringRef InFile,
+                                                       std::string &Sysroot,
+                                                       std::string &OutputFile,
+                                                       raw_ostream *&OS) {
+  // If no output file was provided, figure out where this module would go
+  // in the module cache.
+  if (CI.getFrontendOpts().OutputFile.empty()) {
+    HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+    llvm::SmallString<256> ModuleFileName(HS.getModuleCachePath());
+    llvm::sys::path::append(ModuleFileName, 
+                            CI.getLangOpts().CurrentModule + ".pcm");
+    CI.getFrontendOpts().OutputFile = ModuleFileName.str();
+  }
+  
+  // We use createOutputFile here because this is exposed via libclang, and we
+  // must disable the RemoveFileOnSignal behavior.
+  // We use a temporary to avoid race conditions.
+  OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
+                           /*RemoveFileOnSignal=*/false, InFile,
+                           /*Extension=*/"", /*useTemporary=*/true);
+  if (!OS)
+    return true;
+  
+  OutputFile = CI.getFrontendOpts().OutputFile;
+  return false;
+}
+
 ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
                                                  StringRef InFile) {
   return new ASTConsumer();

Modified: cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp?rev=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp (original)
+++ cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp Tue Nov 15 18:09:06 2011
@@ -50,6 +50,7 @@
   case EmitObj:                return new EmitObjAction();
   case FixIt:                  return new FixItAction();
   case GenerateModule:         return new GeneratePCHAction(true);
+  case GenerateModuleFromMap:  return new GenerateModuleAction;
   case GeneratePCH:            return new GeneratePCHAction(false);
   case GeneratePTH:            return new GeneratePTHAction();
   case InitOnly:               return new InitOnlyAction();

Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Tue Nov 15 18:09:06 2011
@@ -800,6 +800,46 @@
   return StringRef();
 }
 
+bool HeaderSearch::loadModuleMapFile(const FileEntry *File) {
+  const DirectoryEntry *Dir = File->getDir();
+  
+  llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
+    = DirectoryHasModuleMap.find(Dir);
+  if (KnownDir != DirectoryHasModuleMap.end())
+    return !KnownDir->second;
+  
+  bool Result = ModMap.parseModuleMapFile(File);
+  DirectoryHasModuleMap[Dir] = !Result;
+  return Result;
+}
+
+ModuleMap::Module *HeaderSearch::getModule(StringRef Name, bool AllowSearch) {
+  if (ModuleMap::Module *Module = ModMap.findModule(Name))
+    return Module;
+  
+  if (!AllowSearch)
+    return 0;
+  
+  for (unsigned I = 0, N = SearchDirs.size(); I != N; ++I) {
+    if (!SearchDirs[I].isNormalDir())
+      continue;
+    
+    switch (loadModuleMapFile(SearchDirs[I].getDir())) {
+    case LMM_AlreadyLoaded:
+    case LMM_InvalidModuleMap:
+    case LMM_NoDirectory:
+      break;
+        
+    case LMM_NewlyLoaded:
+      if (ModuleMap::Module *Module = ModMap.findModule(Name))
+        return Module;
+      break;
+    }
+  }
+  
+  return 0;
+}
+
 HeaderSearch::LoadModuleMapResult 
 HeaderSearch::loadModuleMapFile(StringRef DirName) {
   if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))

Added: cfe/trunk/test/Modules/Inputs/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=144736&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/module.map (added)
+++ cfe/trunk/test/Modules/Inputs/module.map Tue Nov 15 18:09:06 2011
@@ -0,0 +1,4 @@
+module diamond_top { umbrella "diamond_top.h" }
+module diamond_left { umbrella "diamond_left.h" }
+module diamond_right { umbrella "diamond_right.h" }
+module diamond_bottom { umbrella "diamond_bottom.h" }

Modified: cfe/trunk/test/Modules/diamond.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/diamond.c?rev=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/test/Modules/diamond.c (original)
+++ cfe/trunk/test/Modules/diamond.c Tue Nov 15 18:09:06 2011
@@ -20,8 +20,9 @@
   lr.left = 17;
 }
 
-// RUN: %clang_cc1 -emit-module -o %T/diamond_top.pcm %S/Inputs/diamond_top.h
-// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_left.pcm %S/Inputs/diamond_left.h
-// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_right.pcm %S/Inputs/diamond_right.h
-// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_bottom.pcm %S/Inputs/diamond_bottom.h
-// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash %s -verify
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -emit-module-from-map -fmodule-cache-path %t -fmodule-name=diamond_top %S/Inputs/module.map
+// RUN: %clang_cc1 -emit-module-from-map -fmodule-cache-path %t -fmodule-name=diamond_left %S/Inputs/module.map
+// RUN: %clang_cc1 -emit-module-from-map -fmodule-cache-path %t -fmodule-name=diamond_right %S/Inputs/module.map
+// RUN: %clang_cc1 -emit-module-from-map -fmodule-cache-path %t -fmodule-name=diamond_bottom %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodule-cache-path %t %s -verify

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=144736&r1=144735&r2=144736&view=diff
==============================================================================
--- cfe/trunk/test/Modules/normal-module-map.cpp (original)
+++ cfe/trunk/test/Modules/normal-module-map.cpp Tue Nov 15 18:09:06 2011
@@ -1,8 +1,6 @@
 // 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
 
-// FIXME: The expected error here is temporary, since we don't yet have the
-// logic to build a module from a module map.
 #include "Umbrella/Umbrella.h"
 
 int getUmbrella() { 
@@ -11,6 +9,8 @@
 
 __import_module__ Umbrella2;
 
+// FIXME: The expected error here is temporary, since we don't yet have the
+// logic to build a module from a module map.
 #include "a1.h" // expected-error{{module 'libA' not found}}
 #include "b1.h"
 #include "nested/nested2.h"





More information about the cfe-commits mailing list