diff --git a/cmake/modules/RootNewMacros.cmake b/cmake/modules/RootNewMacros.cmake index 311480b0d703f..e523fd68499bf 100644 --- a/cmake/modules/RootNewMacros.cmake +++ b/cmake/modules/RootNewMacros.cmake @@ -190,7 +190,7 @@ macro(REFLEX_GENERATE_DICTIONARY dictionary) endmacro() #--------------------------------------------------------------------------------------------------- -#---ROOT_GENERATE_DICTIONARY( result_var ) +#---ROOT_GET_LIBRARY_OUTPUT_DIR( result_var ) # Returns the path to the .so file or .dll file. In the latter case Windows defines the dll files as # executables and puts them in the $ROOTSYS/bin folder. function(ROOT_GET_LIBRARY_OUTPUT_DIR result) diff --git a/core/base/src/TSystem.cxx b/core/base/src/TSystem.cxx index bea171a7d7acd..2b2e22e7b52c0 100644 --- a/core/base/src/TSystem.cxx +++ b/core/base/src/TSystem.cxx @@ -2,7 +2,7 @@ // Author: Fons Rademakers 15/09/95 /************************************************************************* - * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -29,6 +29,7 @@ allows a simple partial implementation for new OS'es. #include #include +#include #include "Riostream.h" #include "TSystem.h" #include "TApplication.h" @@ -3523,21 +3524,45 @@ int TSystem::CompileMacro(const char *filename, Option_t *opt, rcling += "\" -f \""; rcling.Append(dict).Append("\" "); - if (useCxxModules) - rcling += " -cxxmodule "; - - if (produceRootmap) { + if (produceRootmap && !useCxxModules) { rcling += " -rml " + libname + " -rmf \"" + libmapfilename + "\" "; - } - rcling.Append(GetIncludePath()).Append(" -D__ACLIC__ "); - if (produceRootmap) { rcling.Append("-DR__ACLIC_ROOTMAP "); } + rcling.Append(GetIncludePath()).Append(" -D__ACLIC__ "); if (gEnv) { TString fromConfig = gEnv->GetValue("ACLiC.IncludePaths",""); - rcling.Append(fromConfig).Append(" \""); + rcling.Append(fromConfig); } - rcling.Append(filename_fullpath).Append("\" \"").Append(linkdef).Append("\"");; + + // Create a modulemap + // FIXME: Merge the modulemap generation from cmake and here in rootcling. + if (useCxxModules && produceRootmap) { + rcling += " -cxxmodule "; + // TString moduleMapFileName = file_dirname + "/" + libname + ".modulemap"; + TString moduleName = libname + "_ACLiC_dict"; + if (moduleName.BeginsWith("lib")) + moduleName = moduleName.Remove(0, 3); + TString moduleMapName = moduleName + ".modulemap"; + TString moduleMapFullPath = build_loc + "/" + moduleMapName; + // A modulemap may exist from previous runs, overwrite it. + if (verboseLevel > 3 && !AccessPathName(moduleMapFullPath)) + ::Info("ACLiC", "File %s already exists!", moduleMapFullPath.Data()); + + std::string curDir = ROOT::FoundationUtils::GetCurrentDir(); + std::string relative_path = ROOT::FoundationUtils::MakePathRelative(filename_fullpath.Data(), curDir); + std::ofstream moduleMapFile(moduleMapFullPath, std::ios::out); + moduleMapFile << "module \"" << moduleName << "\" {" << std::endl; + moduleMapFile << " header \"" << relative_path << "\"" << std::endl; + moduleMapFile << " export *" << std::endl; + moduleMapFile << " link \"" << libname_ext << "\"" << std::endl; + moduleMapFile << "}" << std::endl; + moduleMapFile.close(); + gInterpreter->RegisterPrebuiltModulePath(build_loc.Data(), moduleMapName.Data()); + rcling.Append(" \"-fmodule-map-file=" + moduleMapFullPath + "\" "); + } + + rcling.Append(" \"").Append(filename_fullpath).Append("\" "); + rcling.Append("\"").Append(linkdef).Append("\""); // ======= Run rootcling if (withInfo) { diff --git a/core/dictgen/src/rootcling_impl.cxx b/core/dictgen/src/rootcling_impl.cxx index 42bd238673763..b76d26050eb11 100644 --- a/core/dictgen/src/rootcling_impl.cxx +++ b/core/dictgen/src/rootcling_impl.cxx @@ -19,6 +19,7 @@ const char *shortHelp = #include "RConfigure.h" #include +#include #include #include @@ -186,42 +187,6 @@ static void EmitEnums(const std::vector &enumvec) } } -//////////////////////////////////////////////////////////////////////////////// - -static void GetCurrentDirectory(std::string &output) -{ - char fixedLength[1024]; - char *currWorkDir = fixedLength; - size_t len = 1024; - char *result = currWorkDir; - - do { - if (result == 0) { - len = 2 * len; - if (fixedLength != currWorkDir) { - delete [] currWorkDir; - } - currWorkDir = new char[len]; - } -#ifdef WIN32 - result = ::_getcwd(currWorkDir, len); -#else - result = getcwd(currWorkDir, len); -#endif - } while (result == 0 && errno == ERANGE); - - output = currWorkDir; - output += '/'; -#ifdef WIN32 - // convert backslashes into forward slashes - std::replace(output.begin(), output.end(), '\\', '/'); -#endif - - if (fixedLength != currWorkDir) { - delete [] currWorkDir; - } -} - //////////////////////////////////////////////////////////////////////////////// /// Returns the executable path name, used e.g. by SetRootSys(). @@ -259,35 +224,6 @@ const char *GetExePath() return exepath.c_str(); } - - -//////////////////////////////////////////////////////////////////////////////// -/// Convert to path relative to $PWD -/// If that's not what the caller wants, she should pass -I to rootcling and a -/// different relative path to the header files. - -static std::string GetRelocatableHeaderName(const std::string &header, const std::string ¤tDirectory) -{ - std::string result(header); - - const char *currWorkDir = currentDirectory.c_str(); - size_t lenCurrWorkDir = strlen(currWorkDir); - if (result.substr(0, lenCurrWorkDir) == currWorkDir) { - // Convert to path relative to $PWD. - // If that's not what the caller wants, she should pass -I to rootcling and a - // different relative path to the header files. - result.erase(0, lenCurrWorkDir); - } - if (gBuildingROOT) { - // For ROOT, convert module directories like core/base/inc/ to include/ - int posInc = result.find("/inc/"); - if (posInc != -1) { - result = /*std::string("include") +*/ result.substr(posInc + 5, -1); - } - } - return result; -} - //////////////////////////////////////////////////////////////////////////////// bool Namespace__HasMethod(const clang::NamespaceDecl *cl, const char *name, @@ -3664,6 +3600,29 @@ class TRootClingCallbacks : public cling::InterpreterCallbacks { } } } + + // rootcling pre-includes things such as Rtypes.h. This means that ACLiC can + // call rootcling asking it to create a module for a file with no #includes + // but relying on things from Rtypes.h such as the ClassDef macro. + // + // When rootcling starts building a module, it becomes resilient to the + // outside environment and pre-included files have no effect. This hook + // informs rootcling when a new submodule is being built so that it can + // make Core.Rtypes.h visible. + virtual void EnteredSubmodule(clang::Module* M, + clang::SourceLocation ImportLoc, + bool ForPragma) { + assert(M); + using namespace clang; + if (llvm::StringRef(M->Name).endswith("ACLiC_dict")) { + Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor(); + HeaderSearch& HS = PP.getHeaderSearchInfo(); + // FIXME: Reduce to Core.Rtypes.h. + Module* CoreModule = HS.lookupModule("Core", /*AllowSearch*/false); + assert(M && "Must have module Core"); + PP.makeModuleVisible(CoreModule, ImportLoc); + } + } }; //////////////////////////////////////////////////////////////////////////////// @@ -3810,9 +3769,6 @@ int RootClingMain(int argc, bool ignoreExistingDict = false; bool requestAllSymbols = isDeep; - std::string currentDirectory; - GetCurrentDirectory(currentDirectory); - ic = 1; if (!gDriverConfig->fBuildingROOTStage1) { if (strcmp("-rootbuild", argv[ic]) == 0) { @@ -3991,7 +3947,6 @@ int RootClingMain(int argc, bool selSyntaxOnly = false; bool noIncludePaths = false; bool cxxmodule = false; - bool isAclic = false; // Collect the diagnostic pragmas linked to the usage of -W // Workaround for ROOT-5656 @@ -4137,8 +4092,6 @@ int RootClingMain(int argc, } ic++; } - if (liblistPrefix.length()) - isAclic = true; // Check if we have a multi dict request but no target library if (multiDict && sharedLibraryPathName.empty()) { @@ -4372,6 +4325,8 @@ int RootClingMain(int argc, AddPlatformDefines(clingArgs); + std::string currentDirectory = ROOT::FoundationUtils::GetCurrentDir(); + std::string interpPragmaSource; std::string includeForSource; std::string interpreterDeclarations; @@ -4418,7 +4373,9 @@ int RootClingMain(int argc, if (fullheader[fullheader.length() - 1] == '+') { fullheader.erase(fullheader.length() - 1); } - std::string header(isSelectionFile ? fullheader : GetRelocatableHeaderName(fullheader, currentDirectory)); + std::string header( + isSelectionFile ? fullheader + : ROOT::FoundationUtils::MakePathRelative(fullheader, currentDirectory, gBuildingROOT)); interpPragmaSource += std::string("#include \"") + header + "\"\n"; if (!isSelectionFile) { @@ -4895,14 +4852,14 @@ int RootClingMain(int argc, } modGen.WriteRegistrationSource(dictStream, fwdDeclnArgsToKeepString, headersClassesMapString, fwdDeclsString, - extraIncludes, cxxmodule && !isAclic); + extraIncludes, cxxmodule); // If we just want to inline the input header, we don't need // to generate any files. if (!inlineInputHeader) { // Write the module/PCH depending on what mode we are on if (modGen.IsPCH()) { if (!GenerateAllDict(modGen, CI, currentDirectory)) return 1; - } else if (cxxmodule && !isAclic) { + } else if (cxxmodule) { if (!CheckModuleValid(modGen, resourceDir, interp, linkdefFilename, moduleName.str())) return 1; } @@ -5017,7 +4974,6 @@ int RootClingMain(int argc, // Manually call end of translation unit because we never call the // appropriate deconstructors in the interpreter. This writes out the C++ // module file that we currently generate. - if (!isAclic) { cling::Interpreter::PushTransactionRAII RAII(&interp); CI->getSema().getASTConsumer().HandleTranslationUnit(CI->getSema().getASTContext()); diff --git a/core/foundation/CMakeLists.txt b/core/foundation/CMakeLists.txt index 2046fa79d552c..4ceb70de3c1ad 100644 --- a/core/foundation/CMakeLists.txt +++ b/core/foundation/CMakeLists.txt @@ -17,6 +17,7 @@ set(Foundation_dict_headers ) set(sources + src/FoundationUtils.cxx src/RConversionRuleParser.cxx src/TClassEdit.cxx ) diff --git a/core/foundation/res/ROOT/FoundationUtils.hxx b/core/foundation/res/ROOT/FoundationUtils.hxx new file mode 100644 index 0000000000000..9fe42fd0a4ff9 --- /dev/null +++ b/core/foundation/res/ROOT/FoundationUtils.hxx @@ -0,0 +1,45 @@ +/// \file FoundationUtils.hxx +/// +/// \brief The file contains utilities which are foundational and could be used +/// across the core component of ROOT. +/// +/// +/// \author Vassil Vassilev +/// +/// \date June, 2019 +/// +/************************************************************************* + * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_CORE_FOUNDATION_FOUNDATIONUTILS_HXX +#define ROOT_CORE_FOUNDATION_FOUNDATIONUTILS_HXX + +#include + +namespace ROOT { +namespace FoundationUtils { + + ///\returns the $PWD. + std::string GetCurrentDir(); + + ///\returns the relative path of \c path with respect to \c base. + /// For instance, for path being "/a/b/c/d" and base "/a/b", returns "c/d". + /// + ///\param path - the input path + /// + ///\param base - the base path to be removed from \c path. + /// + ///\param isBuildingROOT - if true, it converts module directories such as + /// core/base/inc/ to include/ + std::string MakePathRelative(const std::string &path, const std::string &base, + bool isBuildingROOT = false); + + } // namespace FoundationUtils +} // namespace ROOT + +#endif // ROOT_CORE_FOUNDATION_FOUNDATIONUTILS_HXX diff --git a/core/foundation/src/FoundationUtils.cxx b/core/foundation/src/FoundationUtils.cxx new file mode 100644 index 0000000000000..420870bdbd02d --- /dev/null +++ b/core/foundation/src/FoundationUtils.cxx @@ -0,0 +1,92 @@ +/// \file FoundationUtils.hxx +/// +/// \brief The file contains utilities which are foundational and could be used +/// across the core component of ROOT. +/// +/// +/// \author Vassil Vassilev +/// +/// \date June, 2019 +/// +/************************************************************************* + * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#include + +#include + +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif // _WIN32 + +namespace ROOT { +namespace FoundationUtils { +std::string GetCurrentDir() +{ + char fixedLength[1024]; + char *currWorkDir = fixedLength; + size_t len = 1024; + char *result = currWorkDir; + + do { + if (result == 0) { + len = 2 * len; + if (fixedLength != currWorkDir) { + delete[] currWorkDir; + } + currWorkDir = new char[len]; + } +#ifdef WIN32 + result = ::_getcwd(currWorkDir, len); +#else + result = getcwd(currWorkDir, len); +#endif + } while (result == 0 && errno == ERANGE); + + std::string output = currWorkDir; + output += '/'; +#ifdef WIN32 + // convert backslashes into forward slashes + std::replace(output.begin(), output.end(), '\\', '/'); +#endif + + if (fixedLength != currWorkDir) { + delete[] currWorkDir; + } + return output; +} + +std::string MakePathRelative(const std::string &path, const std::string &base, bool isBuildingROOT /* = false*/) +{ + std::string result(path); + + const char *currWorkDir = base.c_str(); + size_t lenCurrWorkDir = strlen(currWorkDir); + if (result.substr(0, lenCurrWorkDir) == currWorkDir) { + // Convert to path relative to $PWD. + // If that's not what the caller wants, she should pass -I to rootcling and a + // different relative path to the header files. + result.erase(0, lenCurrWorkDir); + } + // FIXME: This is not a generic approach for an interface. We should rework + // this part. + if (isBuildingROOT) { + // For ROOT, convert module directories like core/base/inc/ to include/ + int posInc = result.find("/inc/"); + if (posInc != -1) { + result = /*std::string("include") +*/ result.substr(posInc + 5, -1); + } + } + return result; +} +} // namespace FoundationUtils +} // namespace ROOT diff --git a/core/meta/inc/TInterpreter.h b/core/meta/inc/TInterpreter.h index 87fd9f09fd988..92fa634d544ce 100644 --- a/core/meta/inc/TInterpreter.h +++ b/core/meta/inc/TInterpreter.h @@ -176,6 +176,8 @@ class TInterpreter : public TNamed { virtual Long_t ProcessLine(const char *line, EErrorCode *error = 0) = 0; virtual Long_t ProcessLineSynch(const char *line, EErrorCode *error = 0) = 0; virtual void PrintIntro() = 0; + virtual bool RegisterPrebuiltModulePath(const std::string& FullPath, + const std::string& ModuleMapName = "module.modulemap") const = 0; virtual void RegisterModule(const char* /*modulename*/, const char** /*headers*/, const char** /*includePaths*/, diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx index e569497d4f549..3dfefd098c18f 100644 --- a/core/metacling/src/TCling.cxx +++ b/core/metacling/src/TCling.cxx @@ -1044,38 +1044,9 @@ std::string TCling::ToString(const char* type, void* obj) return fInterpreter->toString(type, obj); } -//////////////////////////////////////////////////////////////////////////////// -///\returns true if the module map was loaded, false on error or if the map was -/// already loaded. -static bool RegisterPrebuiltModulePath(clang::Preprocessor& PP, - const std::string& FullPath) { - assert(llvm::sys::path::is_absolute(FullPath)); - FileManager& FM = PP.getFileManager(); - // FIXME: In a ROOT session we can add an include path (through .I /inc/path) - // We should look for modulemap files there too. - const DirectoryEntry *DE = FM.getDirectory(FullPath); - if (DE) { - HeaderSearch& HS = PP.getHeaderSearchInfo(); - const FileEntry *FE = HS.lookupModuleMapFile(DE, /*IsFramework*/ false); - const auto &ModPaths = HS.getHeaderSearchOpts().PrebuiltModulePaths; - bool pathExists = std::find(ModPaths.begin(), ModPaths.end(), FullPath) != ModPaths.end(); - if (!pathExists) - HS.getHeaderSearchOpts().AddPrebuiltModulePath(FullPath); - // FIXME: Calling IsLoaded is slow! Replace this with the appropriate - // call to the clang::ModuleMap class. - if (FE && !gCling->IsLoaded(FE->getName().data())) { - assert(!pathExists && "Prebuilt module path was added w/o loading a modulemap!"); - if (!HS.loadModuleMapFile(FE, /*IsSystem*/ false)) - return true; - Error("TCling::LoadModule", "Could not load modulemap in the current directory"); - } - } - return false; -} - //////////////////////////////////////////////////////////////////////////////// ///\returns true if the module was loaded. -static bool LoadModule(const std::string &ModuleName, cling::Interpreter &interp, bool Complain = true) +static bool LoadModule(const std::string &ModuleName, cling::Interpreter &interp) { // When starting up ROOT, cling would load all modulemap files on the include // paths. However, in a ROOT session, it is very common to run aclic which @@ -1084,11 +1055,10 @@ static bool LoadModule(const std::string &ModuleName, cling::Interpreter &interp // // Before failing, try loading the modulemap in the current folder and try // loading the requested module from it. - clang::Preprocessor& PP = interp.getCI()->getPreprocessor(); std::string currentDir = gSystem->WorkingDirectory(); assert(!currentDir.empty()); - RegisterPrebuiltModulePath(PP, currentDir); - return interp.loadModule(ModuleName, Complain); + gCling->RegisterPrebuiltModulePath(currentDir); + return interp.loadModule(ModuleName, /*Complain=*/true); } //////////////////////////////////////////////////////////////////////////////// @@ -1720,6 +1690,45 @@ namespace { } +//////////////////////////////////////////////////////////////////////////////// +///\returns true if the module map was loaded, false on error or if the map was +/// already loaded. +bool TCling::RegisterPrebuiltModulePath(const std::string &FullPath, + const std::string &ModuleMapName /*= "module.modulemap"*/) const +{ + assert(llvm::sys::path::is_absolute(FullPath)); + Preprocessor &PP = fInterpreter->getCI()->getPreprocessor(); + FileManager &FM = PP.getFileManager(); + // FIXME: In a ROOT session we can add an include path (through .I /inc/path) + // We should look for modulemap files there too. + const DirectoryEntry *DE = FM.getDirectory(FullPath); + if (DE) { + HeaderSearch &HS = PP.getHeaderSearchInfo(); + HeaderSearchOptions &HSOpts = HS.getHeaderSearchOpts(); + const auto &ModPaths = HSOpts.PrebuiltModulePaths; + bool pathExists = std::find(ModPaths.begin(), ModPaths.end(), FullPath) != ModPaths.end(); + if (!pathExists) + HSOpts.AddPrebuiltModulePath(FullPath); + // We cannot use HS.lookupModuleMapFile(DE, /*IsFramework*/ false); + // because its internal call to getFile has CacheFailure set to true. + // In our case, modulemaps can appear any time due to ACLiC. + // Code copied from HS.lookupModuleMapFile. + llvm::SmallString<256> ModuleMapFileName(DE->getName()); + llvm::sys::path::append(ModuleMapFileName, ModuleMapName); + const FileEntry *FE = FM.getFile(ModuleMapFileName, /*openFile*/ false, + /*CacheFailure*/ false); + + // FIXME: Calling IsLoaded is slow! Replace this with the appropriate + // call to the clang::ModuleMap class. + if (FE && !this->IsLoaded(FE->getName().data())) { + if (!HS.loadModuleMapFile(FE, /*IsSystem*/ false)) + return true; + Error("RegisterPrebuiltModulePath", "Could not load modulemap in %s", ModuleMapFileName.c_str()); + } + } + return false; +} + //////////////////////////////////////////////////////////////////////////////// /// List of dicts that have the PCM information already in the PCH. static const std::unordered_set gIgnoredPCMNames = {"libCore", @@ -2026,13 +2035,17 @@ void TCling::RegisterModule(const char* modulename, // specifying the relevant include paths we should try loading the // modulemap next to the library location. clang::Preprocessor &PP = TheSema.getPreprocessor(); - // Can be nullptr in case of libCore. - if (dyLibName) - RegisterPrebuiltModulePath(PP, llvm::sys::path::parent_path(dyLibName)); + std::string ModuleMapName; + if (isACLiC) + ModuleMapName = ModuleName + ".modulemap"; + else + ModuleMapName = "module.modulemap"; + RegisterPrebuiltModulePath(llvm::sys::path::parent_path(dyLibName), + ModuleMapName); // FIXME: We should only complain for modules which we know to exist. For example, we should not complain about // modules such as GenVector32 because it needs to fall back to GenVector. - ModuleWasSuccessfullyLoaded = LoadModule(ModuleName, *fInterpreter, /*Complain=*/ !isACLiC); + ModuleWasSuccessfullyLoaded = LoadModule(ModuleName, *fInterpreter); if (!ModuleWasSuccessfullyLoaded) { // Only report if we found the module in the modulemap. clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo(); diff --git a/core/metacling/src/TCling.h b/core/metacling/src/TCling.h index f5f0984672c80..901509b2e566f 100644 --- a/core/metacling/src/TCling.h +++ b/core/metacling/src/TCling.h @@ -223,6 +223,8 @@ class TCling final : public TInterpreter { Long_t ProcessLineAsynch(const char* line, EErrorCode* error = 0); Long_t ProcessLineSynch(const char* line, EErrorCode* error = 0); void PrintIntro(); + bool RegisterPrebuiltModulePath(const std::string& FullPath, + const std::string& ModuleMapName = "module.modulemap") const; void RegisterModule(const char* modulename, const char** headers, const char** includePaths, diff --git a/core/metacling/src/TClingCallbacks.cxx b/core/metacling/src/TClingCallbacks.cxx index ded9679001a45..b4a1226d6be4b 100644 --- a/core/metacling/src/TClingCallbacks.cxx +++ b/core/metacling/src/TClingCallbacks.cxx @@ -97,8 +97,8 @@ void TClingCallbacks::InclusionDirective(clang::SourceLocation sLoc/*HashLoc*/, llvm::StringRef /*RelativePath*/, const clang::Module * Imported) { // We found a module. Do not try to do anything else. + Sema &SemaR = m_Interpreter->getSema(); if (Imported) { - Sema &SemaR = m_Interpreter->getSema(); // FIXME: We should make the module visible at that point. if (!SemaR.isModuleVisible(Imported)) ROOT::TMetaUtils::Info("TClingCallbacks::InclusionDirective", @@ -124,7 +124,6 @@ void TClingCallbacks::InclusionDirective(clang::SourceLocation sLoc/*HashLoc*/, std::string localString(FileName.str()); - Sema &SemaR = m_Interpreter->getSema(); DeclarationName Name = &SemaR.getASTContext().Idents.get(localString.c_str()); LookupResult RHeader(SemaR, Name, sLoc, Sema::LookupOrdinaryName); diff --git a/interpreter/cling/include/cling/Interpreter/InterpreterCallbacks.h b/interpreter/cling/include/cling/Interpreter/InterpreterCallbacks.h index 5100fc7398ab8..0c1a7f0a9c399 100644 --- a/interpreter/cling/include/cling/Interpreter/InterpreterCallbacks.h +++ b/interpreter/cling/include/cling/Interpreter/InterpreterCallbacks.h @@ -110,6 +110,9 @@ namespace cling { llvm::StringRef /*SearchPath*/, llvm::StringRef /*RelativePath*/, const clang::Module* /*Imported*/) {} + virtual void EnteredSubmodule(clang::Module* M, + clang::SourceLocation ImportLoc, + bool ForPragma) {} virtual bool FileNotFound(llvm::StringRef FileName, llvm::SmallVectorImpl& RecoveryPath); diff --git a/interpreter/cling/lib/Interpreter/CIFactory.cpp b/interpreter/cling/lib/Interpreter/CIFactory.cpp index 951f14005d291..fc4120cfd4d80 100644 --- a/interpreter/cling/lib/Interpreter/CIFactory.cpp +++ b/interpreter/cling/lib/Interpreter/CIFactory.cpp @@ -1237,6 +1237,13 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, PP.getTargetInfo().getTriple()); } + for (const auto& Filename : FrontendOpts.ModuleMapFiles) { + if (auto* File = FM.getFile(Filename)) + PP.getHeaderSearchInfo().loadModuleMapFile(File, /*IsSystem*/ false); + else + CI->getDiagnostics().Report(diag::err_module_map_not_found) << Filename; + } + return CI.release(); // Passes over the ownership to the caller. } diff --git a/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp b/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp index 2106eca257095..b4087935cfe16 100644 --- a/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp +++ b/interpreter/cling/lib/Interpreter/InterpreterCallbacks.cpp @@ -49,6 +49,12 @@ namespace cling { SearchPath, RelativePath, Imported); } + void EnteredSubmodule(clang::Module* M, + clang::SourceLocation ImportLoc, + bool ForPragma) override { + m_Callbacks->EnteredSubmodule(M, ImportLoc, ForPragma); + } + virtual bool FileNotFound(llvm::StringRef FileName, llvm::SmallVectorImpl& RecoveryPath) { if (m_Callbacks) diff --git a/interpreter/cling/lib/Interpreter/MultiplexInterpreterCallbacks.h b/interpreter/cling/lib/Interpreter/MultiplexInterpreterCallbacks.h index 7d2bfe0ea3203..61b9180ef9e7e 100644 --- a/interpreter/cling/lib/Interpreter/MultiplexInterpreterCallbacks.h +++ b/interpreter/cling/lib/Interpreter/MultiplexInterpreterCallbacks.h @@ -41,6 +41,12 @@ namespace cling { Imported); } + void EnteredSubmodule(clang::Module* M, clang::SourceLocation ImportLoc, + bool ForPragma) override { + for (auto&& cb : m_Callbacks) + cb->EnteredSubmodule(M, ImportLoc, ForPragma); + } + bool FileNotFound(llvm::StringRef FileName, llvm::SmallVectorImpl& RecoveryPath) override { bool result = false; diff --git a/interpreter/llvm/src/tools/clang/include/clang/Lex/PPCallbacks.h b/interpreter/llvm/src/tools/clang/include/clang/Lex/PPCallbacks.h index 81c3bd7d14ec5..6f4d95c351699 100644 --- a/interpreter/llvm/src/tools/clang/include/clang/Lex/PPCallbacks.h +++ b/interpreter/llvm/src/tools/clang/include/clang/Lex/PPCallbacks.h @@ -128,6 +128,29 @@ class PPCallbacks { const Module *Imported) { } + /// Callback invoked whenever a submodule was entered. + /// + /// \param M The submodule we have entered. + /// + /// \param ImportLoc The location of import directive token. + /// + /// \param ForPragma If entering from pragma directive. + /// + virtual void EnteredSubmodule(Module *M, SourceLocation ImportLoc, + bool ForPragma) { } + + /// Callback invoked whenever a submodule was left. + /// + /// \param M The submodule we have left. + /// + /// \param ImportLoc The location of import directive token. + /// + /// \param ForPragma If entering from pragma directive. + /// + virtual void LeftSubmodule(Module *M, SourceLocation ImportLoc, + bool ForPragma) { } + + /// \brief Callback invoked whenever there was an explicit module-import /// syntax. /// @@ -365,6 +388,18 @@ class PPChainedCallbacks : public PPCallbacks { Imported); } + void EnteredSubmodule(Module *M, SourceLocation ImportLoc, + bool ForPragma) override { + First->EnteredSubmodule(M, ImportLoc, ForPragma); + Second->EnteredSubmodule(M, ImportLoc, ForPragma); + } + + void LeftSubmodule(Module *M, SourceLocation ImportLoc, + bool ForPragma) override { + First->LeftSubmodule(M, ImportLoc, ForPragma); + Second->LeftSubmodule(M, ImportLoc, ForPragma); + } + void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, const Module *Imported) override { First->moduleImport(ImportLoc, Path, Imported); diff --git a/interpreter/llvm/src/tools/clang/lib/Lex/PPLexerChange.cpp b/interpreter/llvm/src/tools/clang/lib/Lex/PPLexerChange.cpp index 36d7028da6886..d66060ab10577 100644 --- a/interpreter/llvm/src/tools/clang/lib/Lex/PPLexerChange.cpp +++ b/interpreter/llvm/src/tools/clang/lib/Lex/PPLexerChange.cpp @@ -665,6 +665,8 @@ void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc, BuildingSubmoduleStack.push_back( BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState, PendingModuleMacroNames.size())); + if (Callbacks) + Callbacks->EnteredSubmodule(M, ImportLoc, ForPragma); return; } @@ -709,6 +711,9 @@ void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc, BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState, PendingModuleMacroNames.size())); + if (Callbacks) + Callbacks->EnteredSubmodule(M, ImportLoc, ForPragma); + // Switch to this submodule as the current submodule. CurSubmoduleState = &State; @@ -749,6 +754,10 @@ Module *Preprocessor::LeaveSubmodule(bool ForPragma) { // are tracking macro visibility, don't build any, and preserve the list // of pending names for the surrounding submodule. BuildingSubmoduleStack.pop_back(); + + if (Callbacks) + Callbacks->LeftSubmodule(LeavingMod, ImportLoc, ForPragma); + makeModuleVisible(LeavingMod, ImportLoc); return LeavingMod; } @@ -833,6 +842,9 @@ Module *Preprocessor::LeaveSubmodule(bool ForPragma) { BuildingSubmoduleStack.pop_back(); + if (Callbacks) + Callbacks->LeftSubmodule(LeavingMod, ImportLoc, ForPragma); + // A nested #include makes the included submodule visible. makeModuleVisible(LeavingMod, ImportLoc); return LeavingMod;