Undefined symbols error in root dictionary made with rootcint

Hi rooters,

This post is related to this recent discussion about wrapping a c++ class for python using rootcint. I am trying to do a more complicated implementation of the example done in the linked discussion, and running into some issues. I am easily able to wrap a simple c++ class using the method in the link, but things fell apart when I tried to use some non-standard c++ objects in the class. In particular, I cannot use the RAT toolkit, which is a c++ wrapper for GEANT4. If I leave out the lines of code that use RAT, the method below works fine, but if I include them, I get an unidentified symbol error. As a disclaimer, I am new to this type of thing, so I may missing something obvious. Here is a simplified version of what I am doing: I have a class AnalysisManager…
AnalysisManager.h:

# include "TFile.h"

class AnalysisManager{
	public:
		TFile* f;
		AnalysisManager() {}
		virtual void func(TFile* f);
};

AnalysisManager.cc:

# include "AnalysisManager.h"
# include "TFile.h"
# include <RAT/DS/Root.hh>

void AnalysisManager::func(TFile* f) { 
	f->ls(); // does some stuff with the file
	RAT::DS::Root* r = new RAT::DS::Root(); // this causes the unidentified symbol error
	delete r;
}

I have a file called AnalysisManagerLinkDef.h which rootcint can use to make a root dictionary. AnalysisManagerLinkDef.h:

#ifdef __MAKECINT__
#pragma link C++ class AnalysisManager+;
#endif

With these three files, I can use rootcint to make the dictionary (analysismanagerdict.cxx) and compile it and the AnalysisManager.cc file into a shared library called libanalysismanager.so:

$ rootcint -f analysismanagerdict.cxx -c AnalysisManager.h AnalysisManagerLinkDef.h
$ g++ -I$ROOTSYS/include -c -fpic analysismanagerdict.cxx -o ./analysismanagerdict.o
$ g++ -I$ROOTSYS/include -I$RATROOT/include -L$RATROOT/lib -lrat -c -fpic AnalysisManager.cc -o ./AnalysisManager.o
$ g++ -shared -fpic AnalysisManager.o analysismanagerdict.o -o ./libanalysismanager.so

Then I can use the c++ object in python with

from ctypes import *
import ROOT as rt

lib = cdll.LoadLibrary('./libanalysismanager.so')
am = rt.AnalysisManager()
f = rt.Tfile("myfile.root", "RECREATE")
am.func(f)

This works flawlessly if the line using RAT in AnalysisManager.cc is commented out (and the delete). However, with that line included, I get the following error:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    lib = cdll.LoadLibrary('./libanalysismanager.so')
  File "/usr/lib/python2.7/ctypes/__init__.py", line 440, in LoadLibrary
    return self._dlltype(name)
  File "/usr/lib/python2.7/ctypes/__init__.py", line 362, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: ./libanalysismanager.so: undefined symbol: _ZTVN3RAT2DS4RootE

It may be that I have misunderstood the uses of rootcint, but it would be great to get this working if not! Please let me know your thoughts.

-JSS

ROOT Version: 5.34/07
Platform: Ubuntu 16.04.6
Compiler: g++ 49.3-13ubuntu2


You need to either load the ‘RAT toolkit library’ on the python prompt or (better) add them to the shared library link line.

Cheers,
Philippe.

Hi @pcanal,

Sorry for the lack of follow up on my end, I keep having to put this on the back burner.

I updated the compilation process so I link the RAT toolkit in the shared library with no success. Is there anything obvious about my compilation process that is causing me issues?

rootcint -f analysismanagerdict.cxx -c AnalysisManager.h AnalysisManagerLinkDef.h
g++ -I$ROOTSYS/include -c -fpic analysismanagerdict.cxx -o ./analysismanagerdict.o
g++ -I$ROOTSYS/include -I$RATROOT/include -c -fpic AnalysisManager.cc -o ./AnalysisManager.o
g++ -I$ROOTSYS/include -I$RATROOT/include -L$RATROOT/lib -shared -fpic AnalysisManager.o analysismanagerdict.o -o ./libanalysismanager.so -lrat

Thanks again for the continued help.

Best,
jss

What does ldd libanalysismanager.so prints?
What does nm -A libanalysismanager.so | grep _ZTVN3RAT2DS4RootE prints?
What does nm -A $RATROOT/lib/librat.so | grep _ZTVN3RAT2DS4RootE prints?

Hi Philippe,

gives

linux-vdso.so.1 =>  (0x00007ffedbd76000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9bfb19b000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9bfae8b000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9bfac73000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9bfa8a3000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f9bfbaeb000)

After the above changes to the compilation process, the error I get lists a different symbol as the culprit: _ZN12TMatrixTBaseIdE4DrawEPKc.
When I check _ZTVN3RAT2DS4RootE it seems to be a weak symbol:

gives

libanalysismanager.so:00000000005aad80 V _ZTVN3RAT2DS4RootE

I did just realize that the rat library Im trying to link is a static library (librat.a) which maybe changes things?

gives

/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:Gsim.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:InMicroCLEANProducer.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:DSWriter.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:InROOTProducer.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:OutNetProc.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:OutROOTProc.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:InDCDAQProducer.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:InAvalancheProducer.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:InFlatProducer.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:InDEAP1Producer.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:DSReader.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:InNetProducer.o:                 U _ZTVN3RAT2DS4RootE
/data/snoplus/home/jschrott/.opt/rat/rat-vuv/lib/librat.a:RAT_Dict_jailbreak.o:0000000000000000 V _ZTVN3RAT2DS4RootE

Analogous commands for the _ZN12TMatrixTBaseIdE4DrawEPKc symbol show that it is undefined in both librat.a and libanalysismanager.so (only "U"s). Does this mean this is just a ROOT symbol?

Sorry for the massive dump of output!

-jss

So the include of the RAT library works and you now need to add the necessary ROOT library. Here that is -lMatrix.

Cheers,
Philippe.

1 Like

Adding -L$ROOTSYS/lib and -lMatrix made another undefined symbol error pop up (_ZTV9TRotation).

I then tried to link all the libraries in ROOT and RAT by replaceing the -l arguments with

$ROOTSYS/lib/*.a $ROOTSYS/lib/*.so $RATROOT/lib/*.a $RATROOT/lib/*.so

This produced yet another undefined symbol error (BZ2_bzread). I don’t know where this symbol could be coming from if not from RAT or ROOT. Any thoughts? I also tried loading all the ROOT libraries using root-config --glibs and root-config --libs

Best,
jss

You need to add “-lPhysics -lMatrix”:

[...]$ c++filt _ZTV9TRotation
[...]$ grep TRotation ${ROOTSYS}/lib/*.rootmap

Don’t do that :slight_smile: :slight_smile:

Just add the one you need ( -lPhysics in this case)

Haha roger that! Ok this brings us to the last mystery: I’ve linked -lrat -lMatrix -lPhysics. Now I get an undefined symbol error for BZ2_bzread. Using the same tricks as before:

$ nm -A libanalysismanager.so | grep BZ2_bzread
libanalysismanager.so:                 U BZ2_bzread
$ nm -A $RATROOT/lib/librat.a | grep BZ2_bzread
$RATROOT/lib/librat.a:ReadFile.o:                 U BZ2_bzread

So BZ2_bzread is a referenced but undefined symbol in librat.a. It is not anywhere in ROOT though:

$ nm -A $ROOTSYS/lib/* | grep BZ2_bzread
--nothing-- #except errors about unrecognized rootmap files of course

Moreover:

$ c++filt BZ2_bzread
BZ2_bzread
$ grep BZ2_bzread ${ROOTSYS}/lib/*.rootmap
--nothing--

I was thinking that BZ2_bzread might be a symbols from GEANT4 which I cant unmangle it because maybe GEANT4 was compiled with a different compiler (RAT is a wrapper for GEANT4 as a reminder). So I tried the following, but also got nothing.

$ nm -A <MyGEANT4>/lib/* | grep BZ2_bzread
--nothing__

-jss

Google says its from -lbz2

Success! I was stuck in rat-land for so long, I forgot something might actually come from another standard lib. The final list of required libraries was -lrat -lMatrix -lPhysics -lThread -lHist -lbz2. Thank you @pcanal for all the help! Not sure which reply to mark as the solution, but the case is definitely closed.

-jss

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