Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions README/ReleaseNotes/v640/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion cmake/modules/RootMacros.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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$<JOIN:$<REMOVE_DUPLICATES:$<FILTER:${include_dirs},EXCLUDE,^$>>,;-I>"
"$<$<BOOL:$<JOIN:${definitions},>>:-D$<JOIN:${definitions},;-D>>"
DEPENDS ${headerfiles} ${selectionfile} ${ARG_DEPENDS}
Expand Down
8 changes: 8 additions & 0 deletions config/rootrc.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions core/base/src/TROOT.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions core/meta/inc/TInterpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 16 additions & 0 deletions core/meta/src/TClass.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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.
Expand Down
44 changes: 44 additions & 0 deletions core/metacling/src/TCling.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ void TCling__PrintStackTrace() {

extern "C" int TCling__LoadLibrary(const char *library)
{
gCling->RegisterAutoLoadedLibrary(library);
return gSystem->Load(library, "", false);
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;

}
Expand Down Expand Up @@ -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);
}

Expand Down
6 changes: 6 additions & 0 deletions core/metacling/src/TCling.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ class TCling final : public TInterpreter {
std::set<size_t> fLookedUpClasses; // Set of classes for which headers were looked up already
std::set<size_t> fPayloads; // Set of payloads
std::set<const char*> fParsedPayloadsAddresses; // Set of payloads which were parsed
std::set<std::string> fAutoParseClasses; // Set of classes for which we autoparsed a header
std::set<std::string> fAutoLoadedLibraries; // Set of libraries that were autoloaded
std::hash<std::string> fStringHashFunction; // A simple hashing function
std::unordered_set<const clang::NamespaceDecl*> fNSFromRootmaps; // Collection of namespaces fwd declared in the rootmaps
TObjArray* fRootmapFiles; // Loaded rootmap files.
Expand Down Expand Up @@ -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<std::string>& 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);
Expand Down Expand Up @@ -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,
Expand All @@ -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;
Expand Down
11 changes: 5 additions & 6 deletions io/io/inc/TStreamerInfoActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename action_t>
void AddAction( action_t action, TConfiguration *conf ) {
Expand All @@ -208,17 +207,17 @@ 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<TLoopConfiguration> fLoopConfig; ///< If this is a bundle of memberwise streaming action, this configures the looping
ActionContainer_t fActions;

void AddToOffset(Int_t delta);
void SetMissing();

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<TLoopConfiguration> 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<TLoopConfiguration> loopConfig);
TActionSequence *CreateSubSequence(const std::vector<Int_t> &element_ids, size_t offset);

TActionSequence *CreateSubSequence(const TIDs &element_ids, size_t offset, SequenceGetter_t create);
Expand Down
2 changes: 1 addition & 1 deletion io/io/src/TBufferFile.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion io/io/src/TBufferText.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading
Loading