Using a dictionary without gSystem->Load

I’m working on a complex cmake-based project, with multiple programs distributed over different directories. Each program is in its own directory, as is the ROOT dictionary directory: GramsDataObj (the project’s name is GramsSim for an experiment called GRAMS).

I’ve gotten everything to work, from LinkDefs to TTrees (getting operator<< to work was a huge pain), except for one annoying thing: I have to include a statement like:

gSystem->Load("GramsDataObj/libGramsSimProjectDataObj.so") 

in order for a program to use the dictionary. I’d rather not hard-code this statement in every one of the programs that has to access the dictionary; I’d prefer for the shared library to be linked with the program during compilation.

I know it’s possible to do this. Before embarking on this project, I set up a kiddie-level test suite. The relevant files for this question are:

STL_TrackList.h = my simple classes
STL_LinkDef.h = the LinkDef file
STLntupleCreateDict.cxx = a program that uses the dictionary

I was able to compile, link, and execute the programs with:

rootcling -f STLntupleDict.cxx STL_TrackList.h STL_LinkDef.h
g++ `root-config --cflags --libs` -shared STLntupleDict.cxx -o STLntupleDict.so -fPIC
g++ `root-config --cflags --libs` STLntupleCreateDict.cxx ./STLntupleDict.so -o STLntupleCreateDict

With this, I was able to run STLntupleCreateDict without needing to use gSystem->Load within the program code. So I know it’s possible.

However, I can’t recreate this behavior in the bigger project, in which I’m using cmake. In the data-object directory GramsDataObj, I have the following lines in my CMakeLists.txt:

# My header files:
file(GLOB headerList ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)

# The source code to compile
file(GLOB DataObjSrc src/*.cc
                    ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc
    )

# To avoid typing:
set(LinkDef ${CMAKE_CURRENT_SOURCE_DIR}/include/LinkDef.hh)
set(Dictionary ${CMAKE_CURRENT_BINARY_DIR}/DataObjDict)
set(LibName ${CMAKE_PROJECT_NAME}DataObj)

# Create the dictionary
ROOT_GENERATE_DICTIONARY ( ${Dictionary} ${headerList} LINKDEF ${LinkDef} )

# Create the dictionary shared library:
add_library (${LibName} SHARED ${Dictionary}.cxx ${DataObjSrc})

The effect of these commands is to create the files I’d expect in my build directory:

# ls GramsDataObj
CMakeFiles  cmake_install.cmake  DataObjDict.cxx  DataObjDict_rdict.pcm  libGramsSimProjectDataObj.so  Makefile

In the CMakeLists.txt for one of the programs that’s going to use the dictionary, I have (among many other lines):

target_link_libraries(${PROG} ${CMAKE_PROJECT_NAME}DataObj )
target_link_libraries(${PROG} ${ROOT_LIBRARIES} )

It seems clear enough: In the dictionary directory, I create dictionary.so file, and in the program directory I link that .so file into the program.

In fact, when I hunt through the myriad work files that cmake creates, I can see ../GramsDataObj/libGramsSimProjectDataObj.so in the list of libraries to be linked (along with, for example, -lRIO and dozens of others).

But if I don’t have the gSystem->Load line in the program’s code, I get error messages that are consistent with the dictionary not being found:

Error in <TTree::Branch>: The pointer specified for EventID is not of a class known to ROOT
Error in <TTree::Branch>: The class requested (map<int,grams::MCTrack>) for the branch "TrackList" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (map<int,grams::MCTrack>) to avoid to write corrupted data.

If the gSystem->Load is present, the program runs without problems.

What am I missing?

Note: There is no MODULE option in my ROOT_GENERATE_DICTIONARY. That’s because I don’t want the dictionary to be created just for a specific executable; I just want the shared library to be compiled, then linked into the programs in other directories. If a MODULE option can be used to specify something other than a target executable, please let me know… at least, if it will help in this case.


ROOT Version: 6.24/06
Platform: AlmaLinux 9
Compiler: 9.5.0


You are probably using one of the platform where you need to use -Wl,--no-as-needed to avoid the linker from dropping libraries that are not directly used.

That did it! I added this link to the CMakeLists.txt file in each of the program directories that used my data objects:

# The following line is needed to make sure DataObj is linked with the executable.                                      
target_link_options(${PROG} PRIVATE "LINKER:-no-as-needed")

I would have rather “attached” this as a property to the dictionary compilation/linking somehow, so that its CMakeLists.txt file would be the only one that would have to be edited. But I’m not facile enough with cmake to figure this out.

Thanks!

Now, if only I could figure out why the dictionaries are always rebuilt when I edit something and rebuild the project, even when I don’t touch the dictionaries. But that’s just a minor inconvenience.

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