diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Basic/FileManager.cpp | 4 | ||||
-rw-r--r-- | lib/Frontend/CompilerInstance.cpp | 78 | ||||
-rw-r--r-- | lib/Lex/HeaderSearch.cpp | 40 |
3 files changed, 117 insertions, 5 deletions
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index 4ac8e4da1d..adc9705405 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -380,6 +380,10 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile) { return &UFE; } +void FileManager::forgetFile(StringRef Filename) { + SeenFileEntries.erase(Filename); +} + const FileEntry * FileManager::getVirtualFile(StringRef Filename, off_t Size, time_t ModificationTime) { diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 1106e48e91..1f1a2f77bb 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -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 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { 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 @@ ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc, 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; diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 36826756b8..5cf65cbb0d 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -98,14 +98,48 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) { 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; } //===----------------------------------------------------------------------===// |