Shared Library Linking in ROOT6 vs ROOT5

Hi All,

I am having trouble migrating code from ROOT 5.34 (where it runs perfectly) up to ROOT6. Currently, the code compiles fine, but I am having trouble with the linking. I feel like this question is pretty straight forward and might be addressed somewhere, but I have found some contradictory/outdated answers, but none that work quite right.

Here is a breakdown of the situation:

We have libraries A, B, C … X, Y, Z. At compile time, A must be compiled first, and libraries B - Y all depend on A and increasingly on each other. But at run time libA loads libZ which does not depend on A (this is somewhat historical since libZ contains a bunch of style options and is fairly ‘unimportant’.)

So, in ROOT 5, libraries A - Z are independently compiled, and can be compiled in roughly any order (after A). Each library follows the same steps: first the source code, then a dictionary is generated with rootcint, then the shared library is compiled. The last step passes that library along with all the libraries it depends on to rlibmap. For example:

# ROOTCINT
$ rootcint -f K_Dict.cc -c -p -I[INCLUDES] K1.hh K2.hh K3.hh LinkDef.hh

# COMPILE DICTIONARY
$ g++ -c [CXXFLAGS] -o K_Dict.o K_Dict.cc

# COMPILE LIBRARY
# Note that this command does not have any linked libraries (-lA -lC) etc
$ g++ -shared [FLAGS] -I[INCLUDES] K1.o K2.o K3.o K_Dict.o -o libK.so 

# CREATE ROOTMAP
$ rlibmap -f -o LIBDIR/libK.rootmap -l libK.so -d libA libC libG -c LinkDef.hh

This created a rootmap file that listed all the classes in libK and all the libraries that need to be loaded in order to load libK.

Ok, so flash to ROOT6. rlibmap is no longer a thing, and rootcint is now a wrapper for rootcling.
So my compile now looks like this:

# ROOTCLING
$ rootcling -rootbuild -f K_Dict.cc -s libK -rmf libK.rootmap -c -p -I[INCLUDES] K1.hh K2.hh K3.hh LinkDef.hh

# COMPILE DICTIONARY
$  g++ -c [CXXFLAGS] -o K_Dict.o K_Dict.cc # same as above

# COMPILE LIBRARY
$ g++ -shared [FLAGS] -I[INCLUDES] K1.o K2.o K3.o  K_Dict.o -o libK.so # same as above

So now the problem is that when I try to load the libraries in ROOT:

root [] gSystem->Load("libK")

It complains that symbols (that can be found in libA) are undefined. Now, I can fix the problem if I add “-lA -lC -lG” to the g++ -shared command so that the libraries are explicitly linked, however this would require that things be compiled in the proper order (i.e. that the library exist at compile time.)

So a few questions:

First of all, am I doing something wrong here? Am I missing something obvious?

Second, what is the purpose of the -rml flag to cling? I see that it is optional, and it sounds like it might be relevant?

Third, what is the purpose of the pcm file? It is placed next to the library and rootmap files, but I am not sure what exactly it is doing, other than that the interpreter complains when its not there. Should I be passing the "-m libA_dict.pcm … " flags to rootcling? Since there seems to be no guarantee that the pcm files passed at compile time are the same as those at run time, I wasn’t sure that this was relevant. Again, this would require compiling in the correct order?

Hopefully that was all clear. Thanks in advance.

Cheers,
–Jon

Hi Jon,

I am not sure I understand the question. If libK depends on libA because this latter contains symbols not present in the former, libK should be linked to libA if not you have undefined symbols, right?

The rml flag specifies the name of the library which should be autoloaded when a class, enum, variable or header file relevant to your selection is encountered.

The pcm file is a special ROOT file and is necessary and should sit next to the library in which the dictionary it refers to has been compiled. It contains metadata to fill the ROOT typesystem at library load time, metadata used to do I/O of selected classes.
The -m flag will be necessary in the future when the pcm files will not be ROOT files anymore but rather clang precompiled modules. It allows to specify a hierarchy, a tiered structure, of pre compiled modules.

Cheers,
Danilo

Hi Danilo,

Thanks for the quick reply.

Yes. But at run time, ROOT and our executables will unravel these dependencies using the rootmap files.

Ok, I think this is the solution to my question. Specifying a string of -rml files will tell ROOT to autoload those libraries at run time. (I thought I had tried this, but I guess not.) So changing the rootcling command to :

$ rootcling -rootbuild -f K_Dict.cc -s libK -rml libA.so -rml libC.so -rml libG.so -rmf libK.rootmap -c -p -I[INCLUDES] K1.hh K2.hh K3.hh LinkDef.hh

appears to fix the problem.

Ok, so if I understand correctly, I should add

-m [PATH]/libA_dict.pcm -m [PATH]/libC_dict.pcm -m [PATH]/libG_dict.pcm

to the rootcling command. This will not do anything right now, but will be needed in the future? But I need to specify an absolute/relative path of the pcm file? There is no flag to specify a set of directories to search in order, similar to the -L flag in the compiler? Is there a reason not to use that type of structure?

Cheers,
–Jon

Hi Jon,

I am glad you could solve your problem with rootmaps: dynamic loading of plugins is a powerful feature of ROOT and is much more advanced in ROOT6 than in ROOT5 - I fully support the idea of relying on it.
As far as tiered pcms are concerned, you are right. They are still in an experimental phase - keeping build system flexible, e.g. specifying the tiered pcm files, is something that will pay in the long term as changing the nature of the pcm files (i.e. from being ROOT files to real pre compiled modules) will be seamlessly accommodated.
We did not consider yet the idea of specifying a “pcm directory”: these files will be located in the library path anyway - the full path should not be needed. If this requirement change, your idea of a “-L” like switch will be implemented with priority: I agree it would make things simpler.

Cheers,
Danilo

Hi there.
I am on Root6.10/08. I compile my macro and move it to another node with the same OS and ROOT versions, but a different user area. When I try to load my so file which has the .pcm file next to it, I get this error:

R__LOAD_LIBRARY(dbxParticle_cpp.so)
dbxParticle_cpp_ACLiC_dict dictionary payload:10:10: fatal error: ‘./dbxParticle.cpp’ file not found
#include “./dbxParticle.cpp”
^
Warning in TInterpreter::TCling::RegisterModule: Problems declaring payload for module dbxParticle_cpp_ACLiC_dict.

Why should a compiled library look for the source code? Am I doing something wrong?
Cheers
G.

Hi,

we in general prefer not to respawn threads which are years old, but let’s dive into this.
How did you build the library?
Under certain circumstances, ROOT6 parses the sources with which dictionaries were generated at runtime.

Cheers,
D

I do this:
gSystem->SetMakeSharedLib(“cd $BuildDir ; c++ -c $Opt -pipe -std=c++11 -m64 -msse -mfpmath=sse -W -Woverloaded-virtual -fPIC -pthread $IncludePath $SourceFiles ; c++ $ObjectFiles -shared -Wl, soname,$LibName.so -m64 -O2 -Wl,–no-undefined -Wl,–as-needed $LinkedLibs -o $SharedLib”);

gROOT->LoadMacro(“dbxParticle.cpp+”);
gROOT->LoadMacro(“dbx_muon.h+”);

Hi,

I suggest to create dictionaries and a proper shared library.
If you want to transport libraries created with aclic, move the so library, the pcm file and the sources too.

Cheers,
D