diff --git a/CMakeLists.txt b/CMakeLists.txt index 957825e88ddac..5dd0b6ea74c5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -343,7 +343,11 @@ endif() if(runtime_cxxmodules) # Dummy target that does nothing, we don't need a PCH for modules. - add_custom_target(onepcm) + # However, we require that TMVA/Graf/Treeplayer are built here as + # we will always load them to workaround the fact that we can't + # load the decls in them via rootmap files (as they are inside + # namespaces which isn't supported). + add_custom_target(onepcm DEPENDS Net MathCore TreeViewer RooStats Hist Gpad TreePlayer RooFit EG RGL TMVA TMVAGui Graf GenVector) else() add_custom_command(OUTPUT etc/allDict.cxx.pch COMMAND ${CMAKE_COMMAND} -E env ROOTIGNOREPREFIX=1 ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/etc/dictpch/makepch.py etc/allDict.cxx.pch ${__allIncludes} -I${CMAKE_BINARY_DIR}/include diff --git a/cmake/modules/RootNewMacros.cmake b/cmake/modules/RootNewMacros.cmake index a4ad269c48b39..d6a5664001989 100644 --- a/cmake/modules/RootNewMacros.cmake +++ b/cmake/modules/RootNewMacros.cmake @@ -366,7 +366,8 @@ function(ROOT_GENERATE_DICTIONARY dictionary) endforeach() endif() - if(runtime_cxxmodules AND ARG_MODULE) + set(runtime_cxxmodules_env) + if(runtime_cxxmodules AND ARG_MODULE AND NOT ARG_MULTIDICT) # FIXME: Once modules work better, we should use some other value like "1" # to disable the module-build remarks from clang. set(runtime_cxxmodules_env "ROOT_MODULES=DEBUG") diff --git a/core/base/inc/TROOT.h b/core/base/inc/TROOT.h index 2717f079c21fd..f7d31ecdee63a 100644 --- a/core/base/inc/TROOT.h +++ b/core/base/inc/TROOT.h @@ -309,7 +309,8 @@ friend TROOT *ROOT::Internal::GetROOT2(); const char* fwdDeclCode, void (*triggerFunc)(), const FwdDeclArgsToKeepCollection_t& fwdDeclsArgToSkip, - const char** classesHeaders); + const char** classesHeaders, + bool hasCxxModule = false); TObject *Remove(TObject*); void RemoveClass(TClass *); void Reset(Option_t *option=""); diff --git a/core/base/src/TROOT.cxx b/core/base/src/TROOT.cxx index 7efe1911841f1..5400ec84dd539 100644 --- a/core/base/src/TROOT.cxx +++ b/core/base/src/TROOT.cxx @@ -258,7 +258,8 @@ namespace { const char* fwdDeclCode, void (*triggerFunc)(), const TROOT::FwdDeclArgsToKeepCollection_t& fwdDeclsArgToSkip, - const char** classesHeaders): + const char **classesHeaders, + bool hasCxxModule): fModuleName(moduleName), fHeaders(headers), fPayloadCode(payloadCode), @@ -266,7 +267,8 @@ namespace { fIncludePaths(includePaths), fTriggerFunc(triggerFunc), fClassesHeaders(classesHeaders), - fFwdNargsToKeepColl(fwdDeclsArgToSkip){} + fFwdNargsToKeepColl(fwdDeclsArgToSkip), + fHasCxxModule(hasCxxModule) {} const char* fModuleName; // module name const char** fHeaders; // 0-terminated array of header files @@ -277,6 +279,7 @@ namespace { const char** fClassesHeaders; // 0-terminated list of classes and related header files const TROOT::FwdDeclArgsToKeepCollection_t fFwdNargsToKeepColl; // Collection of // pairs of template fwd decls and number of + bool fHasCxxModule; // Whether this module has a C++ module alongside it. }; std::vector& GetModuleHeaderInfoBuffer() { @@ -2068,7 +2071,8 @@ void TROOT::InitInterpreter() li->fTriggerFunc, li->fFwdNargsToKeepColl, li->fClassesHeaders, - kTRUE /*lateRegistration*/); + kTRUE /*lateRegistration*/, + li->fHasCxxModule); } GetModuleHeaderInfoBuffer().clear(); @@ -2477,7 +2481,8 @@ void TROOT::RegisterModule(const char* modulename, const char* fwdDeclCode, void (*triggerFunc)(), const TInterpreter::FwdDeclArgsToKeepCollection_t& fwdDeclsArgToSkip, - const char** classesHeaders) + const char** classesHeaders, + bool hasCxxModule) { // First a side track to insure proper end of process behavior. @@ -2539,12 +2544,12 @@ void TROOT::RegisterModule(const char* modulename, // Now register with TCling. if (gCling) { - gCling->RegisterModule(modulename, headers, includePaths, payloadCode, fwdDeclCode, - triggerFunc, fwdDeclsArgToSkip, classesHeaders); + gCling->RegisterModule(modulename, headers, includePaths, payloadCode, fwdDeclCode, triggerFunc, + fwdDeclsArgToSkip, classesHeaders, false, hasCxxModule); } else { - GetModuleHeaderInfoBuffer() - .push_back(ModuleHeaderInfo_t (modulename, headers, includePaths, payloadCode, fwdDeclCode, - triggerFunc, fwdDeclsArgToSkip,classesHeaders)); + GetModuleHeaderInfoBuffer().push_back(ModuleHeaderInfo_t(modulename, headers, includePaths, payloadCode, + fwdDeclCode, triggerFunc, fwdDeclsArgToSkip, + classesHeaders, hasCxxModule)); } } diff --git a/core/dictgen/src/TModuleGenerator.cxx b/core/dictgen/src/TModuleGenerator.cxx index 4abfbbde9cb70..646e0171b3f97 100644 --- a/core/dictgen/src/TModuleGenerator.cxx +++ b/core/dictgen/src/TModuleGenerator.cxx @@ -462,7 +462,7 @@ void TModuleGenerator::WriteRegistrationSource(std::ostream &out, " if (!isInitialized) {\n" " TROOT::RegisterModule(\"" << GetDemangledDictionaryName() << "\",\n" " headers, includePaths, payloadCode, fwdDeclCode,\n" - " TriggerDictionaryInitialization_" << GetDictionaryName() << "_Impl, " << fwdDeclnArgsToKeepString << ", classesHeaders);\n" + " TriggerDictionaryInitialization_" << GetDictionaryName() << "_Impl, " << fwdDeclnArgsToKeepString << ", classesHeaders, " << (fCI->getLangOpts().Modules ? "/*has C++ module*/true" : "/*has no C++ module*/false") << ");\n" " isInitialized = true;\n" " }\n" " }\n" diff --git a/core/meta/inc/TInterpreter.h b/core/meta/inc/TInterpreter.h index b7af7ac610fd3..158e4e7445ee3 100644 --- a/core/meta/inc/TInterpreter.h +++ b/core/meta/inc/TInterpreter.h @@ -154,7 +154,8 @@ class TInterpreter : public TNamed { void (* /*triggerFunc*/)(), const FwdDeclArgsToKeepCollection_t& fwdDeclArgsToKeep, const char** classesHeaders, - Bool_t lateRegistration = false) = 0; + Bool_t lateRegistration = false, + Bool_t hasCxxModule = false) = 0; virtual void RegisterTClassUpdate(TClass *oldcl,DictFuncPtr_t dict) = 0; virtual void UnRegisterTClassUpdate(const TClass *oldcl) = 0; virtual Int_t SetClassSharedLibs(const char *cls, const char *libs) = 0; diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx index e0e343ad6c12e..e468236440166 100644 --- a/core/metacling/src/TCling.cxx +++ b/core/metacling/src/TCling.cxx @@ -1065,8 +1065,10 @@ inline bool TCling::TUniqueString::Append(const std::string& str) return notPresent; } +//////////////////////////////////////////////////////////////////////////////// ///\returns true if the module was loaded. -static bool LoadModule(const std::string &ModuleName, cling::Interpreter &interp) { +static bool LoadModule(const std::string &ModuleName, cling::Interpreter &interp, bool Complain = true) +{ clang::CompilerInstance &CI = *interp.getCI(); assert(CI.getLangOpts().Modules && "Function only relevant when C++ modules are turned on!"); @@ -1080,57 +1082,30 @@ static bool LoadModule(const std::string &ModuleName, cling::Interpreter &interp clang::IdentifierInfo *II = PP.getIdentifierInfo(M->Name); SourceLocation ValidLoc = M->DefinitionLoc; bool success = !CI.getSema().ActOnModuleImport(ValidLoc, ValidLoc, std::make_pair(II, ValidLoc)).isInvalid(); - // Also make the module visible in the preprocessor to export its macros. - PP.makeModuleVisible(M, ValidLoc); - return success; + if (success) { + // Also make the module visible in the preprocessor to export its macros. + PP.makeModuleVisible(M, ValidLoc); + return success; + } + if (Complain) { + if (M->IsSystem) + Error("TCling::LoadModule", "Module %s failed to load", M->Name.c_str()); + else + Info("TCling::LoadModule", "Module %s failed to load", M->Name.c_str()); + } } + if (Complain) + Error("TCling::LoadModule", "Module %s not found!", ModuleName.c_str()); return false; } //////////////////////////////////////////////////////////////////////////////// -/// Loads the basic C++ modules that we require to run any ROOT program. -/// This is just supposed to make the declarations in their headers available -/// to the interpreter. -static void LoadCoreModules(cling::Interpreter &interp) +/// Loads the C++ modules that we require to run any ROOT program. This is just +/// supposed to make a C++ module from a modulemap available to the interpreter. +static void LoadModules(const std::vector &modules, cling::Interpreter &interp) { - clang::CompilerInstance &CI = *interp.getCI(); - // Without modules, this function is just a no-op. - if (!CI.getLangOpts().Modules) - return; - - clang::HeaderSearch &headerSearch = CI.getPreprocessor().getHeaderSearchInfo(); - clang::ModuleMap &moduleMap = headerSearch.getModuleMap(); - // List of core modules we can load, but it's ok if they are missing because - // the system doesn't have these modules. - if (clang::Module *LIBCM = moduleMap.findModule("libc")) - if (!LoadModule(LIBCM->Name, interp)) - Error("TCling::LoadCoreModules", "Cannot load module %s", LIBCM->Name.c_str()); - - if (clang::Module *STLM = moduleMap.findModule("stl")) - if (!LoadModule(STLM->Name, interp)) - Error("TCling::LoadCoreModules", "Cannot load module %s", STLM->Name.c_str()); - - // ROOT_Types is a module outside core because we need C and -no-rtti compatibility. - // Preload it as it is an integral part of module Core. - if (!LoadModule(moduleMap.findModule("ROOT_Types")->Name, interp)) - Error("TCling::LoadCoreModules", "Cannot load module ROOT_Types"); - - if (!LoadModule(moduleMap.findModule("Core")->Name, interp)) - Error("TCling::LoadCoreModules", "Cannot load module Core"); - - if (!LoadModule(moduleMap.findModule("RIO")->Name, interp)) - Error("TCling::LoadCoreModules", "Cannot load module RIO"); - - // Check that the gROOT macro was exported by any core module. - assert(interp.getMacro("gROOT") && "Couldn't load gROOT macro?"); - - // C99 decided that it's a very good idea to name a macro `I` (the letter I). - // This seems to screw up nearly all the template code out there as `I` is - // common template parameter name and iterator variable name. - // Let's follow the GCC recommendation and undefine `I` in case any of the - // core modules have defined it: - // https://www.gnu.org/software/libc/manual/html_node/Complex-Numbers.html - interp.declare("#ifdef I\n #undef I\n #endif\n"); + for (const auto &modName : modules) + LoadModule(modName, interp); } static bool FileExists(const char *file) @@ -1145,6 +1120,23 @@ static bool IsFromRootCling() { return foundSymbol; } +static void loadModulePath(HeaderSearch& hdrSearch, const char* inputPath) { + if (inputPath) { + StringRef path = inputPath; + SmallVector paths; + path.split(paths, ":"); + + for (StringRef path : paths) { + SmallString<128> ModuleMapFilePath = path; + llvm::sys::path::append(ModuleMapFilePath, "module.modulemap"); + + if (auto file = hdrSearch.getFileMgr().getFile(ModuleMapFilePath)) { + hdrSearch.loadModuleMapFile(file, false, FileID()); + } + } + } +} + //////////////////////////////////////////////////////////////////////////////// /// Initialize the cling interpreter interface. @@ -1160,8 +1152,6 @@ TCling::TCling(const char *name, const char *title) #ifdef R__USE_CXXMODULES useCxxModules = true; #endif - if (useCxxModules) - fHeaderParsingOnDemand = false; llvm::install_fatal_error_handler(&exceptionErrorHandler); @@ -1204,6 +1194,7 @@ TCling::TCling(const char *name, const char *title) clingArgsStorage.push_back("-Wno-undefined-inline"); clingArgsStorage.push_back("-fsigned-char"); } + clingArgsStorage.push_back("-DVc_NO_VERSION_CHECK"); std::vector interpArgs; for (std::vector::const_iterator iArg = clingArgsStorage.begin(), @@ -1274,6 +1265,27 @@ TCling::TCling(const char *name, const char *title) static llvm::raw_fd_ostream fMPOuts (STDOUT_FILENO, /*ShouldClose*/false); fMetaProcessor = new cling::MetaProcessor(*fInterpreter, fMPOuts); + if (fInterpreter->getCI()->getLangOpts().Modules) { + HeaderSearch& hdrSearch = fInterpreter->getCI()->getPreprocessor().getHeaderSearchInfo(); + hdrSearch.loadTopLevelSystemModules(); + loadModulePath(hdrSearch, gSystem->GetDynamicPath()); + fInterpreter->getCI()->getHeaderSearchOpts().AddPrebuiltModulePath("."); + + // Setup core C++ modules if we have any to setup. + LoadModules({"libc", "stl", "ROOT_Types", "Core", "RIO"}, *fInterpreter); + + // Check that the gROOT macro was exported by any core module. + assert(fInterpreter->getMacro("gROOT") && "Couldn't load gROOT macro?"); + + // C99 decided that it's a very good idea to name a macro `I` (the letter I). + // This seems to screw up nearly all the template code out there as `I` is + // common template parameter name and iterator variable name. + // Let's follow the GCC recommendation and undefine `I` in case any of the + // core modules have defined it: + // https://www.gnu.org/software/libc/manual/html_node/Complex-Numbers.html + fInterpreter->declare("#ifdef I\n #undef I\n #endif\n"); + } + // For the list to also include string, we have to include it now. // rootcling does parts already if needed, e.g. genreflex does not want using // namespace std. @@ -1293,9 +1305,6 @@ TCling::TCling(const char *name, const char *title) "#include \n"); } - // Setup core C++ modules if we have any to setup. - LoadCoreModules(*fInterpreter); - // We are now ready (enough is loaded) to init the list of opaque typedefs. fNormalizedCtxt = new ROOT::TMetaUtils::TNormalizedCtxt(fInterpreter->getLookupHelper()); fLookupHelper = new ROOT::TMetaUtils::TClingLookupHelper(*fInterpreter, *fNormalizedCtxt, TClingLookupHelper__ExistingTypeCheck, TClingLookupHelper__AutoParse); @@ -1368,6 +1377,11 @@ TCling::~TCling() void TCling::Initialize() { fClingCallbacks->Initialize(); + if (fInterpreter->getCI()->getLangOpts().Modules && !IsFromRootCling()) { + // Load modules that we can't automatically load via rootmap files as they + // contain decls in namespaces which aren't supported. + LoadModules({"TMVA", "EG", "RGL", "RooFit", "TMVAGui", "Gpad", "RooStats", "GenVector", "Hist", "MathCore", "Net", "TreePlayer", "TreeViewer", "Graf"}, *fInterpreter); + } } //////////////////////////////////////////////////////////////////////////////// @@ -1673,7 +1687,8 @@ void TCling::RegisterModule(const char* modulename, void (*triggerFunc)(), const FwdDeclArgsToKeepCollection_t& fwdDeclsArgToSkip, const char** classesHeaders, - Bool_t lateRegistration /*=false*/) + Bool_t lateRegistration /*=false*/, + Bool_t hasCxxModule /*=false*/) { const bool fromRootCling = IsFromRootCling(); // We need the dictionary initialization but we don't want to inject the @@ -1773,7 +1788,22 @@ void TCling::RegisterModule(const char* modulename, } // if (dyLibName) } // if (!lateRegistration) - if (hasHeaderParsingOnDemand && fwdDeclsCode){ + clang::Sema &TheSema = fInterpreter->getSema(); + bool ModuleWasSuccessfullyLoaded = false; + if (hasCxxModule) { + std::string ModuleName = llvm::StringRef(modulename).substr(3).str(); + ModuleWasSuccessfullyLoaded = LoadModule(ModuleName, *fInterpreter); + if (!ModuleWasSuccessfullyLoaded) { + // Only report if we found the module in the modulemap. + clang::Preprocessor &PP = TheSema.getPreprocessor(); + clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo(); + clang::ModuleMap &moduleMap = headerSearch.getModuleMap(); + if (moduleMap.findModule(ModuleName)) + Info("TCling::RegisterModule", "Module %s in modulemap failed to load.", ModuleName.c_str()); + } + } + + if (!ModuleWasSuccessfullyLoaded && hasHeaderParsingOnDemand && fwdDeclsCode){ // We now parse the forward declarations. All the classes are then modified // in order for them to have an external lexical storage. std::string fwdDeclsCodeLessEnums; @@ -1910,21 +1940,7 @@ void TCling::RegisterModule(const char* modulename, if (fClingCallbacks) oldValue = SetClassAutoloading(false); - clang::Sema &TheSema = fInterpreter->getSema(); - bool ModuleWasSuccessfullyLoaded = false; - if (TheSema.getLangOpts().Modules) { - std::string ModuleName = llvm::StringRef(modulename).substr(3).str(); - ModuleWasSuccessfullyLoaded = LoadModule(ModuleName, *fInterpreter); - if (!ModuleWasSuccessfullyLoaded) { - // Only report if we found the module in the modulemap. - clang::Preprocessor &PP = TheSema.getPreprocessor(); - clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo(); - clang::ModuleMap &moduleMap = headerSearch.getModuleMap(); - if (moduleMap.findModule(ModuleName)) - Info("TCling::RegisterModule", "Module %s in modulemap failed to load.", ModuleName.c_str()); - } - } { // scope within which diagnostics are de-activated // For now we disable diagnostics because we saw them already at @@ -5104,6 +5120,20 @@ Int_t TCling::LoadLibraryMap(const char* rootmapfile) } if (!skip) { void* dirp = gSystem->OpenDirectory(d); + + // Load the modulemap from the dir and add it to the prebuilt module + // path. + // FIXME: This is ROOT quality code, refactor me. + fInterpreter->getCI()->getHeaderSearchOpts().AddPrebuiltModulePath(d.Data()); + auto& hdrSearch = fInterpreter->getCI()->getPreprocessor().getHeaderSearchInfo(); + SmallString<128> ModuleMapFilePath = StringRef(d.Data()); + llvm::sys::path::append(ModuleMapFilePath, "module.modulemap"); + + if (auto file = hdrSearch.getFileMgr().getFile(ModuleMapFilePath)) { + hdrSearch.loadModuleMapFile(file, false, FileID()); + } + + if (dirp) { if (gDebug > 3) { Info("LoadLibraryMap", "%s", d.Data()); diff --git a/core/metacling/src/TCling.h b/core/metacling/src/TCling.h index f726cf5ecea0c..11ec4c950ea9f 100644 --- a/core/metacling/src/TCling.h +++ b/core/metacling/src/TCling.h @@ -205,7 +205,8 @@ class TCling : public TInterpreter { void (*triggerFunc)(), const FwdDeclArgsToKeepCollection_t& fwdDeclsArgToSkip, const char** classesHeaders, - Bool_t lateRegistration = false); + Bool_t lateRegistration = false, + Bool_t hasCxxModule = false); void RegisterTClassUpdate(TClass *oldcl,DictFuncPtr_t dict); void UnRegisterTClassUpdate(const TClass *oldcl); diff --git a/interpreter/llvm/src/tools/clang/include/clang/Basic/SourceManager.h b/interpreter/llvm/src/tools/clang/include/clang/Basic/SourceManager.h index 0b0534406f4c0..6f6fb80bc6fe6 100644 --- a/interpreter/llvm/src/tools/clang/include/clang/Basic/SourceManager.h +++ b/interpreter/llvm/src/tools/clang/include/clang/Basic/SourceManager.h @@ -625,11 +625,66 @@ class SourceManager : public RefCountedBase { /// expansion. SmallVector LocalSLocEntryTable; + template + class SparseVector { + typedef std::array Chunk; + std::vector Chunks; + std::size_t realSize = 0; + std::size_t allocatedChunks = 0; + + Chunk *getChunk(std::size_t i) { + std::size_t ChunkIndex = i / ChunkSize; + + Chunk* Result = Chunks.at(ChunkIndex); + if (Result == nullptr) { + Result = new Chunk(); + Chunks[ChunkIndex] = Result; + allocatedChunks++; + } + return Result; + } + public: + SparseVector() { + } + + typedef T value_type; + + T& operator[](std::size_t i) { + Chunk *C = getChunk(i); + std::size_t Rem = i % ChunkSize; + return (*C)[Rem]; + } + + std::size_t size() const { + return realSize; + } + + std::size_t capacity() const { + return allocatedChunks * ChunkSize; + } + + void resize(std::size_t s) { + realSize = s; + Chunks.resize((s / ChunkSize) + 1); + } + + void clear() { + Chunks.clear(); + realSize = 0; + allocatedChunks = 0; + } + + bool empty() const { + return realSize == 0; + } + }; + /// \brief The table of SLocEntries that are loaded from other modules. /// /// Negative FileIDs are indexes into this table. To get from ID to an index, /// use (-ID - 2). - mutable SmallVector LoadedSLocEntryTable; + mutable SparseVector LoadedSLocEntryTable; + //mutable SmallVector LoadedSLocEntryTable; /// \brief The starting offset of the next local SLocEntry. ///