Reading ROOT files with minimal dependencies

Hello,

I’m developing a C++ software, which is going to read and write ROOT files. Because my program will be distributed across multiple platforms, I carefully weigh every library dependency that I introduce into my build chain. For this reason, I’m not too excited about linking against the entire ROOT framework just to be able to read/write files.

My question is: since besides files and trees, I technically do not need any of the advanced analysis, plotting and fitting features of ROOT, is there a possibility to minimize the footprint of ROOT in my software? Can I just link against a small self-contained subset of ROOT without making my software heavy? If so, can I link ROOT statically into my program, so that I do not have to worry about whether my users have the correct ROOT version installed?

Alternatively, I found projects like UpROOT that bring native support for ROOT I/O to Python. Do you know if there exists something like UpROOT but for C++?

Many thanks for any advice you can provide.
Best, Petr

You could probably compile ROOT activating the option minimal when calling CMake. You’ll only need then libRIO, libCore and libThread. Building ROOT from source - ROOT

There is also GitHub - JuliaHEP/UnROOT.jl: Native Julia I/O package to work with CERN ROOT files objects (TTree and RNTuple)

1 Like

You could probably compile ROOT activating the option minimal when calling CMake.

I just tried it locally with the latest stable version. The difference is about 3K compilation steps (7K with minimal, 10K with default options). Would this be consistent with your expectations? …or am I doing something wrong?

Yep, that sounds reasonable.
To further reduce the size, you would need external LLVM, so forcing builtin_LLVM=OFF

But then some issues might appear:

So, I tried turning builtin_clang and builtin_llvm off. Unfortunately on my bleeding-edge Linux distribution, ROOT complains that my installed versions of llvm and clang are too new (I have llvm v17, ROOT prefers v13). When I have time, I will repeat this test in my continuous integration, which is running the oldest Linux we support (Ubuntu Focal), and report back.

In the meantime, let me return to one question I asked earlier: is it possible to link with ROOT statically (provided that -fPIC is enabled, of course)?

Static: It’s not officially supported I believe. You can force it by hand, but, see:
https://its.cern.ch/jira/browse/ROOT-6446

@amadio and @hahnjo might give you better hints.

See also:

(since I am being ping’ed…)

you could also use C-bindings to groot (IIRC, that’s what Julia is doing for xrootd: they are generating C-bindings to Go-HEP’s package xrootd (at least, that’s what they were doing at some point…)

Go is building assets statically by default (and has a great story for cross-compiling pure-Go projects. groot is such a thing)

Static: It’s not officially supported I believe.

I see. I think I will not be using that, then. I think we have successfully managed to narrow my use case down to linking dynamically with just libRIO, libCore and libThread to get the I/O part working. I will try my best to use distribution-provided ROOT package, but if unavailable (vcpkg, I am looking at you) I will have to integrate ROOT as a submodule and include it with -Dminimal=ON in my CMake project.

One more follow-up question: is there a way to explicitly disable ROOT’s global state objects (gStyle, gDirectory etc.) and signal handlers (I am using my own crash handling system)? If I move forward with integrating ROOT in my program, I would really like it to have as small memory footprint as possible.

you could also use C-bindings to groot

Interesting suggestion, I will have to investigate that. Naïvely, going from C++ to Go and back to C/C++ seems like an interoperability nightmare. However, I will try to whip up a small demo to see if this would bring any value to my project.

Mmm try maybe with defining a ~/.rootrc custom file in your home (see root/config/rootrc.in at master · root-project/root · GitHub), or calling instead gEnv->SetValue(“Root.ErrorHandlers”, 0)

I don’t think so.

a colleague of mine did something along these lines (they weren’t wrapping groot, but fmom, although, from the point of view of the mechanics of wrapping Go code, it’s kind of the same):

Naïvely, going from C++ to Go and back to C/C++ seems like an interoperability nightmare

Note that groot isn’t calling into C/C++, it’s a reimplementation of (a subset of) ROOT in pure-Go.
so you’d “just” call [C++ → C-shim → Go]. (you still don’t want to do that in a very tight loop, though.)

Related also: Minimal installation for basic IO · Issue #6471 · root-project/root · GitHub

For better (it does provide services and feature) or worse, they can not be turned off.

and signal handlers (I am using my own crash handling system)?

Yes either via the rootrc (probably the best in your case) or a call to

gSystem->ResetSignals();

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.