Errors: Linking
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:-
- The default constructor
- The virtual destructor
Missing ROOT generated Code
If you are generating a ROOT class dictionary entry:-
- There is a ClassDef in the header file.
- There is a ClassImp in the implimentation file.
- There is not a semicolon after either the ClassDef or ClassImp.
Placing a semicolon there results in a failure to expand the macro correctly
so some of the CINT generated code is lost.
- There is an entry for the class in the LinkDef.h
- rootcint, which processes the header files generates no errors.
- For template code (but remember warning about templates in
Commit Code to the Repository) there have to be
ClassDefT and ClassDefT2 in the header and a ClassImpT in the
implimentation file. The LinkDef.h has to any entries for all
instantiated template classes and these must precede any normal classes.
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:-
- Always check that your LinkDef.h declares them to ensure that the
dictionary is complete. Also make sure you don't accidentally declare
them twice!
- CINT generates a copy constructor for your class so, if you class
has other objects as embedded data members, rather than just pointers,
make sure that they have an accessible copy constructors too. For example
TCollection
has a private copy constructor as the ROOT team did not want users
taking copies of collections accidentally. So if you want to include
objects that derived from TCollection, you must define your own copy
constructor.
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>)