diff --git a/README/ReleaseNotes/v640/index.md b/README/ReleaseNotes/v640/index.md index 088e26e083750..bf2ae6264b139 100644 --- a/README/ReleaseNotes/v640/index.md +++ b/README/ReleaseNotes/v640/index.md @@ -71,10 +71,22 @@ The following people have contributed to this new version: ## Core Libraries -- ROOT now adds a RUNPATH to compiled macros. This ensures that when compiled macros are loaded, they load the libraries that belong to the ROOT installation +* ROOT now adds a RUNPATH to compiled macros. This ensures that when compiled macros are loaded, they load the libraries that belong to the ROOT installation that compiled the macro. See [TSystem::SetMakeSharedLib()](https://root.cern.ch/doc/master/classTSystem.html#a80cd12e064e2285b35e9f39b5111d20e) for customising or disabling the RUNPATH. -- `rootcling` fails if no selection rule is specified and if the creation of a C++ module is not requested. +* `rootcling` fails if no selection rule is specified and if the creation of a C++ module is not requested. +* To ease debugging of unwanted auto-parsing triggered by TClass::GetClass, two new features are introduced: +* * Give access to the list of classes that triggered auto-parsing: +``` +// Print the list +gInterpreter->Print("autoparsed"); +// Get the list/set: +((TCling*)gInterpreter)->GetAutoParseClasses(); +``` +* * Auto-parsing of header files can now be explicitly disabled during the execution of TClass::GetClass; +for example, this can be used to enforce that no header is loaded for I/O operations. To disable the +auto-parsing during `TClass::GetClass`, you can either set the shell environment variable +`ROOT_DISABLE_TCLASS_GET_CLASS_AUTOPARSING` (to anything) or set the `rootrc` key `Root.TClass.GetClass.AutoParsing` to `false`. ## Geometry diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index c969b5cf62ca8..6b0a0702a6826 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -194,7 +194,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 06fd91e69d6f6..265d80e5d4026 100644 --- a/config/rootrc.in +++ b/config/rootrc.in @@ -618,3 +618,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 57f56133d00cb..700e01f15ce09 100644 --- a/core/base/src/TROOT.cxx +++ b/core/base/src/TROOT.cxx @@ -2204,6 +2204,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 b8969d77dc2d7..137f09b0bcd8c 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" @@ -2969,6 +2970,11 @@ TVirtualIsAProxy* TClass::GetIsAProxy() const /// If silent is 'true', do not warn about missing dictionary for the class. /// (typically used for classes that are used only for transient members) /// Returns `nullptr` in case class is not found. +/// +/// To completely disallow auto-parsing during TClass::GetClass, you can either +/// set the shell environment variable `ROOT_DISABLE_TCLASS_GET_CLASS_AUTOPARSING` +/// (to anything) or set the `rootrc` key `Root.TClass.GetClass.AutoParsing` to +/// `false`. TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent) { @@ -3053,6 +3059,16 @@ TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent, size_t hi // continue as before ... } + bool disableAutoParsing = gInterpreter->IsAutoParsingSuspended(); + // We could get the user choice from: + // - TClass::SetGetClassAutoParsing + static const bool requestDisableAutoParsing = + !gEnv->GetValue("Root.TClass.GetClass.AutoParsing", true) || + gSystem->Getenv("ROOT_DISABLE_TCLASS_GET_CLASS_AUTOPARSING") != nullptr; + if (requestDisableAutoParsing) + 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 79b6f4ab2e4dd..2184303c5fe51 100644 --- a/core/metacling/src/TCling.cxx +++ b/core/metacling/src/TCling.cxx @@ -348,6 +348,7 @@ void TCling__PrintStackTrace() { extern "C" int TCling__LoadLibrary(const char *library) { + gCling->RegisterAutoLoadedLibrary(library); return gSystem->Load(library, "", false); } @@ -2706,6 +2707,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. @@ -3467,6 +3496,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. @@ -6593,6 +6630,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; } @@ -6699,6 +6742,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 1f0aa189fd89c..36b1bce8812e1 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; diff --git a/io/io/inc/TStreamerInfoActions.h b/io/io/inc/TStreamerInfoActions.h index 40f2ac9cf8419..f09054389579a 100644 --- a/io/io/inc/TStreamerInfoActions.h +++ b/io/io/inc/TStreamerInfoActions.h @@ -191,9 +191,8 @@ namespace TStreamerInfoActions { SetBit((UInt_t)EStatusBits::kVectorPtrLooper); fActions.reserve(maxdata); }; - ~TActionSequence() override { - delete fLoopConfig; - } + // We have no owner pointer, so the default is perfect. + ~TActionSequence() override = default; template void AddAction( action_t action, TConfiguration *conf ) { @@ -208,7 +207,7 @@ namespace TStreamerInfoActions { } TVirtualStreamerInfo *fStreamerInfo; ///< StreamerInfo used to derive these actions. - TLoopConfiguration *fLoopConfig; ///< If this is a bundle of memberwise streaming action, this configures the looping + std::unique_ptr fLoopConfig; ///< If this is a bundle of memberwise streaming action, this configures the looping ActionContainer_t fActions; void AddToOffset(Int_t delta); @@ -216,9 +215,9 @@ namespace TStreamerInfoActions { TActionSequence *CreateCopy(); static TActionSequence *CreateReadMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy); - static TActionSequence *CreateReadMemberWiseActions(TVirtualStreamerInfo &info, TLoopConfiguration *loopConfig); // 2nd arg should be unique_ptr + static TActionSequence *CreateReadMemberWiseActions(TVirtualStreamerInfo &info, std::unique_ptr loopConfig); static TActionSequence *CreateWriteMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy); - static TActionSequence *CreateWriteMemberWiseActions(TVirtualStreamerInfo &info, TLoopConfiguration *loopConfig); // 2nd arg should be unique_ptr + static TActionSequence *CreateWriteMemberWiseActions(TVirtualStreamerInfo &info, std::unique_ptr loopConfig); TActionSequence *CreateSubSequence(const std::vector &element_ids, size_t offset); TActionSequence *CreateSubSequence(const TIDs &element_ids, size_t offset, SequenceGetter_t create); diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index e6ac648781ec0..30f00b2f10a6f 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -3788,7 +3788,7 @@ Int_t TBufferFile::ApplySequenceVecPtr(const TStreamerInfoActions::TActionSequen Int_t TBufferFile::ApplySequence(const TStreamerInfoActions::TActionSequence &sequence, void *start_collection, void *end_collection) { - TStreamerInfoActions::TLoopConfiguration *loopconfig = sequence.fLoopConfig; + TStreamerInfoActions::TLoopConfiguration *loopconfig = sequence.fLoopConfig.get(); if (gDebug) { // Get the address of the first item for the PrintDebug. diff --git a/io/io/src/TBufferText.cxx b/io/io/src/TBufferText.cxx index dcbe184f2fd77..76e625f8ead24 100644 --- a/io/io/src/TBufferText.cxx +++ b/io/io/src/TBufferText.cxx @@ -140,7 +140,7 @@ Int_t TBufferText::ApplySequence(const TStreamerInfoActions::TActionSequence &se TVirtualStreamerInfo *info = sequence.fStreamerInfo; IncrementLevel(info); - TStreamerInfoActions::TLoopConfiguration *loopconfig = sequence.fLoopConfig; + TStreamerInfoActions::TLoopConfiguration *loopconfig = sequence.fLoopConfig.get(); if (gDebug) { // Get the address of the first item for the PrintDebug. diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 61a046c898297..35f315029fce5 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -1520,9 +1520,9 @@ namespace TStreamerInfoActions static std::unique_ptr CreateReadActionSequence(TStreamerInfo &info, TLoopConfiguration *loopConfig) { - TLoopConfiguration *localLoopConfig = loopConfig ? loopConfig->Copy() : nullptr; + std::unique_ptr localLoopConfig{ loopConfig ? loopConfig->Copy() : nullptr }; std::unique_ptr actions( - TActionSequence::CreateReadMemberWiseActions(info, localLoopConfig)); + TActionSequence::CreateReadMemberWiseActions(info, std::move(localLoopConfig))); return actions; } @@ -1532,9 +1532,9 @@ namespace TStreamerInfoActions static std::unique_ptr CreateWriteActionSequence(TStreamerInfo &info, TLoopConfiguration *loopConfig) { - TLoopConfiguration *localLoopConfig = loopConfig ? loopConfig->Copy() : nullptr; + std::unique_ptr localLoopConfig{ loopConfig ? loopConfig->Copy() : nullptr }; std::unique_ptr actions( - TActionSequence::CreateWriteMemberWiseActions(info, localLoopConfig)); + TActionSequence::CreateWriteMemberWiseActions(info, std::move(localLoopConfig))); return actions; } @@ -5171,7 +5171,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr return new TStreamerInfoActions::TActionSequence(0,0); } - TLoopConfiguration *loopConfig = nullptr; + std::unique_ptr loopConfig; if (IsDefaultVector(proxy)) { if (proxy.HasPointers()) { @@ -5182,30 +5182,31 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector. Long_t increment = proxy.GetIncrement(); - loopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE); + loopConfig = std::make_unique(&proxy, increment, /* read */ kTRUE); } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLunorderedset || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLunorderedmultiset || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap || proxy.GetCollectionType() == ROOT::kSTLunorderedmap || proxy.GetCollectionType() == ROOT::kSTLunorderedmultimap) { Long_t increment = proxy.GetIncrement(); - loopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE); + loopConfig = std::make_unique(&proxy, increment, /* read */ kTRUE); // sequence->fLoopConfig = new TAssocLoopConfig(proxy); } else { - loopConfig = new TGenericLoopConfig(&proxy, /* read */ kTRUE); + loopConfig = std::make_unique(&proxy, /* read */ kTRUE); } - return CreateReadMemberWiseActions(*info, loopConfig); + return CreateReadMemberWiseActions(*info, std::move(loopConfig)); } //////////////////////////////////////////////////////////////////////////////// /// Create the bundle of the actions necessary for the streaming memberwise of the content described by 'info' into the collection described by 'proxy' -TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(TVirtualStreamerInfo &info, TLoopConfiguration *loopConfig) +TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(TVirtualStreamerInfo &info, std::unique_ptr inLoopConfig) { UInt_t ndata = info.GetElements()->GetEntriesFast(); TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(&info, ndata); - sequence->fLoopConfig = loopConfig; + sequence->fLoopConfig = std::move(inLoopConfig); + TLoopConfiguration *loopConfig = sequence->fLoopConfig.get(); for (UInt_t i = 0; i < ndata; ++i) { TStreamerElement *element = (TStreamerElement*) info.GetElements()->At(i); @@ -5294,7 +5295,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr return new TStreamerInfoActions::TActionSequence(0,0); } - TLoopConfiguration *loopConfig = nullptr; + std::unique_ptr loopConfig; if (IsDefaultVector(proxy)) { if (proxy.HasPointers()) { @@ -5305,11 +5306,11 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector. Long_t increment = proxy.GetIncrement(); - loopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kFALSE); + loopConfig = std::make_unique(&proxy, increment, /* read */ kFALSE); } else { - loopConfig = new TGenericLoopConfig(&proxy, /* read */ kFALSE); + loopConfig = std::make_unique(&proxy, /* read */ kFALSE); } - return CreateWriteMemberWiseActions(*info, loopConfig); + return CreateWriteMemberWiseActions(*info, std::move(loopConfig)); } //////////////////////////////////////////////////////////////////////////////// @@ -5318,11 +5319,12 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr /// TActionSequence class (stored as public fLoopConfig internally, will be deleted in destructor) \return new /// `sequence` pointer of type TActionSequence, the memory ownership is transferred to caller, must delete it later -TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateWriteMemberWiseActions(TVirtualStreamerInfo &info, TLoopConfiguration *loopConfig) +TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateWriteMemberWiseActions(TVirtualStreamerInfo &info, std::unique_ptr inLoopConfig) { UInt_t ndata = info.GetElements()->GetEntriesFast(); TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(&info, ndata); - sequence->fLoopConfig = loopConfig; + sequence->fLoopConfig = std::move(inLoopConfig); + TLoopConfiguration *loopConfig = sequence->fLoopConfig.get(); for (UInt_t i = 0; i < ndata; ++i) { TStreamerElement *element = (TStreamerElement*) info.GetElements()->At(i); @@ -5434,7 +5436,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(fStreamerInfo, fActions.size(), IsForVectorPtrLooper()); - sequence->fLoopConfig = fLoopConfig ? fLoopConfig->Copy() : 0; + sequence->fLoopConfig.reset(fLoopConfig ? fLoopConfig->Copy() : nullptr); TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end(); for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin(); @@ -5516,7 +5518,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(fStreamerInfo, element_ids.size(), IsForVectorPtrLooper()); - sequence->fLoopConfig = fLoopConfig ? fLoopConfig->Copy() : 0; + sequence->fLoopConfig = std::unique_ptr(fLoopConfig ? fLoopConfig->Copy() : 0); AddToSubSequence(sequence, element_ids, offset, create); @@ -5530,7 +5532,7 @@ TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::Cr TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(fStreamerInfo, element_ids.size(), IsForVectorPtrLooper()); - sequence->fLoopConfig = fLoopConfig ? fLoopConfig->Copy() : 0; + sequence->fLoopConfig.reset(fLoopConfig ? fLoopConfig->Copy() : 0); for(UInt_t id = 0; id < element_ids.size(); ++id) { if ( element_ids[id] < 0 ) { diff --git a/roottest/root/meta/autoloading/headerParsingOnDemand/headerParsingOnDemand.ref b/roottest/root/meta/autoloading/headerParsingOnDemand/headerParsingOnDemand.ref index 36943e5f2cca4..684b009dc6337 100644 --- a/roottest/root/meta/autoloading/headerParsingOnDemand/headerParsingOnDemand.ref +++ b/roottest/root/meta/autoloading/headerParsingOnDemand/headerParsingOnDemand.ref @@ -2,6 +2,7 @@ Processing runFullheaderParsingOnDemand.C... Class name myClass0 Info in : loaded library libFullheaderParsingOnDemand_dictrflx.so for myClass0 Info in : Parsing full payload for myClass0 +Info in : Parsed 1 headers for myClass0 Class name myClass1 Class name myClass1 Class name myClass2