Errors: Linking

Unresolved Global Symbols in Shared Libraries

Managing shared libraries containing compiled user code enhanced with CINT generated member functions is considerably more complex than managing static Fortran libraries for a variety of reasons as discussed below.

Missing User Code

First, of course, you really could have forgotten to write some member function! If the function is defined outside the class definition i.e. in the .cxx file, don't forget to prefix the name with class_name:: to scope it to the class. At a minimum check that you have declared/implemented:-

Missing ROOT generated Code

If you are generating a ROOT class dictionary entry:- One way to check this is simply to create a trivial main program:-
   MyClass myclass;

and the loader will tell you what is missing.

Library Load Order

As with Fortran you must specify libraries are loaded in the correct order. The basic rule is start specific and end generic.

Name Mangling

Function overloading is a fundamental principle in C++ and it differentiates between the various versions based on the type of arguments and return value. It gives each version a unique global symbol so that the linker picks up the correct version. Its does this by adding prefixes and suffices that code for arguments and return type. This process is called "name mangling". It can come as a bit of a shock when the user is presented name that has a name they recognise embedded in alphabetic soup! For example, on my machine:-
   TBranch::TBranch(void)
translates to:-
   __ct__7TBranchXv
To compound the confusion, this is not part of the language standard - it can change with compiler/linker.

You can use the utility c++filt to translate a mangled name e.g.

  c++filt __ct__7TBranchXv
Further, UNIX systems have a utility called nm - that can list global names in an object file or library, both defined and undefined, and show them both in the mangled, and unmangled forms. The default is not standard, so check your man pages to see how to get it to print what you want. Also, the nm output is usually pretty voluminous, so it a good idea to pipe it to more or grep e.g.
   nm $ROOTSYS/lib/libTree.so | grep TBranch::SetAddress  
The MINOS tool find_global_symbol.sh uses nm to search for a symbol, mangled or unmangled, in the offline and ROOT libraries. For example
 find_global_symbol.sh __ct__7TBranchXv
would find all the places where that symbol was used and defined. For help just type
 find_global_symbol.sh

Compiler Generated Symbols

The compiler will require a virtual table for any class that has any virtual function, either in the subclass or inherited. The rules for the creation of this table are compiler specific but typically the table is created in the implementation file so if you don't have one i.e you have a pure abstract class, this could be a problem.

CINT Generated Symbols

The following applies if adding classes the ROOT has to know about:-

ROOT Version Shear

That is to the ROOT binary tools are not compatible with the ROOT source tools. This can happen even if you load everything from a standard ROOT tar file if your local setup differs in any way from the one on which the tar file was made. If you have problems you cannot fix, and whenever switching to a new version of ROOT, it is always safest to rebuild binaries locally. Having got the sources:-
  cd $ROOTSYS
  ./configure linuxegcs (or whatever your system is)

  gmake distclean  <== Important!
  gmake            
  gmake install

Go Back to the The Errors Top Page


Contact: Nick West (n.west1@physics.oxford.ac.uk>)