[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