diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index f8f02be27b490..34a7459b95da5 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -187,7 +187,7 @@ function(REFLEX_GENERATE_DICTIONARY dictionary) OUTPUT ${gensrcdict} ${rootmapname} COMMAND ${ROOT_genreflex_CMD} ARGS ${headerfiles} -o ${gensrcdict} ${rootmapopts} --select=${selectionfile} - --gccxmlpath=${GCCXML_home}/bin ${ARG_OPTIONS} + ${ARG_OPTIONS} "-I$>,;-I>" "$<$>:-D$>" DEPENDS ${headerfiles} ${selectionfile} ${ARG_DEPENDS} diff --git a/config/rootrc.in b/config/rootrc.in index f1bfd4c775200..0b57c1808fc45 100644 --- a/config/rootrc.in +++ b/config/rootrc.in @@ -644,3 +644,11 @@ Rint.Canvas.HighLightColor: 5 # 1 All Branches (default) # Can be overridden by the environment variable ROOT_TTREECACHE_PREFILL # TTreeCache.Prefill: 1 + +# Advanced Debug Settings +# Setting Root.TClass.GetClass.AutoParsing to false +# will disable any auto-parsing execution of `TClass::GetClass`. This will +# result in not being able to find TClass-es when the name requires not-already +# loaded interpreted information (eg. a typedef to be resolved). +# +# Root.TClass.GetClass.AutoParsing: true diff --git a/core/base/src/TROOT.cxx b/core/base/src/TROOT.cxx index b24925bf966e9..5760dc3438b9e 100644 --- a/core/base/src/TROOT.cxx +++ b/core/base/src/TROOT.cxx @@ -2202,6 +2202,9 @@ Int_t TROOT::LoadClass(const char * /*classname*/, const char *libname, // TSystem::Load returns 1 when the library was already loaded, return success in this case. if (err == 1) err = 0; + if (err == 0) + // Register the Autoloading of the library + gCling->RegisterAutoLoadedLibrary(libname); return err; } } else { diff --git a/core/meta/inc/TInterpreter.h b/core/meta/inc/TInterpreter.h index 59f2a09b91039..94980fdb0a7fc 100644 --- a/core/meta/inc/TInterpreter.h +++ b/core/meta/inc/TInterpreter.h @@ -194,6 +194,7 @@ class TInterpreter : public TNamed { virtual void AddAvailableIndentifiers(TSeqCollection&) = 0; virtual void RegisterTClassUpdate(TClass *oldcl,DictFuncPtr_t dict) = 0; virtual void UnRegisterTClassUpdate(const TClass *oldcl) = 0; + virtual void RegisterAutoLoadedLibrary(const char *libname) = 0; virtual Int_t SetClassSharedLibs(const char *cls, const char *libs) = 0; virtual void SetGetline(const char*(*getlineFunc)(const char* prompt), void (*histaddFunc)(const char* line)) = 0; diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index bc34a3e6323e7..e66d4211d9f32 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -55,6 +55,7 @@ In order to access the name of a class within the ROOT type system, the method T #include "TDataType.h" #include "TDatime.h" #include "TEnum.h" +#include "TEnv.h" #include "TError.h" #include "TExMap.h" #include "TFunctionTemplate.h" @@ -3153,6 +3154,17 @@ TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent, size_t hi // continue as before ... } + bool disableAutoParsing = gInterpreter->IsAutoParsingSuspended(); + // FIXME: We need to decided on the interface to disable auto-parsing only during TClass::GetClass. +#ifdef ROOT_DISABLE_TCLASS_GET_CLASS_AUTOPARSING + constexpr bool requestDisableAutoLoading = true; +#else + static const bool requestDisableAutoLoading = !gEnv->GetValue("Root.TClass.GetClass.AutoParsing", true); +#endif + if (requestDisableAutoLoading) + disableAutoParsing = true; + TInterpreter::SuspendAutoParsing autoparseFence(gInterpreter, disableAutoParsing); + // Note: this variable does not always holds the fully normalized name // as there is information from a not yet loaded library or from header // not yet parsed that may be needed to fully normalize the name. diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx index 867c6d9386533..991b52cda289b 100644 --- a/core/metacling/src/TCling.cxx +++ b/core/metacling/src/TCling.cxx @@ -2662,6 +2662,34 @@ void TCling::PrintIntro() { } +//////////////////////////////////////////////////////////////////////////////// +/// Print information about the interpreter. +///\param[in] option Selects the type of information to print. +/// +/// List of currently support options: +/// - autoparsed: Print the list of classes that triggered autoparsing. +void TCling::Print(Option_t *option) const +{ + if (option && *option) { + if (!strcmp(option, "autoparsed")) { + std::cout << "Auto parsed classes:" << std::endl; + for (auto & cls : fAutoParseClasses) { + std::cout << " " << cls << std::endl; + } + } else if (!strcmp(option, "autoloaded")) { + std::cout << "Auto loaded libraries:" << std::endl; + for (auto & lib : fAutoLoadedLibraries) { + std::cout << " " << lib << std::endl; + } + } else { + ::Error("TCling::Print", "Unknown option '%s'", option); + } + } else { + ::Info("TCling::Print", "No options specified"); + } +} + + //////////////////////////////////////////////////////////////////////////////// /// \brief Add a directory to the list of directories in which the /// interpreter looks for include files. @@ -3432,6 +3460,14 @@ static bool StartsWithStrLit(const char *haystack, const char (&needle)[N]) { } } +//////////////////////////////////////////////////////////////////////////////// +/// Register that a library was autoloaded either to provide a 'missing' symbol +/// or to provide a class (see TClass::GetClass and TROOT::LoadClass). +void TCling::RegisterAutoLoadedLibrary(const char *libname) +{ + fAutoLoadedLibraries.insert(libname); +} + //////////////////////////////////////////////////////////////////////////////// /// Register a new shared library name with the interpreter; add it to /// fSharedLibs. @@ -6536,6 +6572,12 @@ UInt_t TCling::AutoParseImplRecurse(const char *cls, bool topLevel) } } + if (nHheadersParsed) { + // Register that we did autoparsing for this class. + fAutoParseClasses.insert(cls); + if (gDebug) + Info("AutoParse", "Parsed %d headers for %s", nHheadersParsed, cls); + } return nHheadersParsed; } @@ -6642,6 +6684,7 @@ void* TCling::LazyFunctionCreatorAutoload(const std::string& mangled_name) { if (!LibLoader(libName)) return nullptr; + fAutoLoadedLibraries.insert(libName); return llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(dlsym_mangled_name); } diff --git a/core/metacling/src/TCling.h b/core/metacling/src/TCling.h index 3fafddd266049..5f9ee0b43bee7 100644 --- a/core/metacling/src/TCling.h +++ b/core/metacling/src/TCling.h @@ -121,6 +121,8 @@ class TCling final : public TInterpreter { std::set fLookedUpClasses; // Set of classes for which headers were looked up already std::set fPayloads; // Set of payloads std::set fParsedPayloadsAddresses; // Set of payloads which were parsed + std::set fAutoParseClasses; // Set of classes for which we autoparsed a header + std::set fAutoLoadedLibraries; // Set of libraries that were autoloaded std::hash fStringHashFunction; // A simple hashing function std::unordered_set fNSFromRootmaps; // Collection of namespaces fwd declared in the rootmaps TObjArray* fRootmapFiles; // Loaded rootmap files. @@ -200,6 +202,7 @@ class TCling final : public TInterpreter { Int_t AutoLoad(const char *classname, Bool_t knowDictNotLoaded = kFALSE) final; Int_t AutoLoad(const std::type_info& typeinfo, Bool_t knowDictNotLoaded = kFALSE) final; Int_t AutoParse(const char* cls) final; + const std::set& GetAutoParseClasses() const { return fAutoParseClasses; } void* LazyFunctionCreatorAutoload(const std::string& mangled_name); bool LibraryLoadingFailed(const std::string&, const std::string&, bool, bool); Bool_t IsAutoLoadNamespaceCandidate(const clang::NamespaceDecl* nsDecl); @@ -240,6 +243,7 @@ class TCling final : public TInterpreter { Longptr_t ProcessLineAsynch(const char* line, EErrorCode* error = nullptr); Longptr_t ProcessLineSynch(const char* line, EErrorCode* error = nullptr) final; void PrintIntro() final; + void Print(Option_t *option="") const final; bool RegisterPrebuiltModulePath(const std::string& FullPath, const std::string& ModuleMapName = "module.modulemap") const final; void RegisterModule(const char* modulename, @@ -256,6 +260,8 @@ class TCling final : public TInterpreter { void RegisterTClassUpdate(TClass *oldcl,DictFuncPtr_t dict) final; void UnRegisterTClassUpdate(const TClass *oldcl) final; + void RegisterAutoLoadedLibrary(const char *libname) final; + Int_t SetClassSharedLibs(const char *cls, const char *libs) final; void SetGetline(const char * (*getlineFunc)(const char* prompt), void (*histaddFunc)(const char* line)) final;