User Tools

Site Tools


root:addclasstoroot

Adding A Class to ROOT

Idea

Instead of writing C++ macros which are intepreted by CINT, one can think of adding a class to ROOT itself. This may be particularly useful for methods that draw and save histograms, apply cuts, etc. The advantage over macros is the stability, as the code is compiled and then executed, and not interpreted by CINT.

Example

Suppose you want to write a (simple) class with a method that creates a ROOT file. You need the following three files: ana.cc, ana.hh and a Makefile.

.cc and .hh File

Your .cc file should look somehow like this:

#include "ana.hh" 

using namespace std;

ClassImp(ana) 
// ----------------------------------------------------- 
// Constructor 
// ----------------------------------------------------- 
ana::ana() { 
  cout << "This is the AnalysisClass,  v 1.0" << endl; 
}
// ------------------------------------------------------ 
// Destructor 
// ------------------------------------------------------ 
ana::~ana(){  
} 
// ---------------------------------------- 
// test 
// ---------------------------------------- 
void ana::test(){ 

  TFile *bla = new TFile("bla.root","CREATE"); 
} 

Your .hh file should look like:

#ifndef ANA 
#define ANA

#include <TObject.h>
#include <TFile.h>
#include <TF1.h>
#include <TROOT.h>

class ana: public TObject { 

public: 

  ana(); 
  ~ana(); 
 
  void test(); 
  
  ClassDef(ana,1) 

}; 

#endif  

Some Notes

  • You must write a constructor (and a destructor) yourself. Normally in C++, if you forget your constructor, the compiler will create a standard-constructor for you. However, if you don't provide a constructor here, you'll run into trouble.
  • The ClassImp(ana) and the ClassDef(ana, 1) are necessary for the full functionality. ana names the class and the number in ClassDef is the VersionID; it has to be greater than zero. ClassDef(…) always has to be the last statement before the closing bracket. These statements are needed to create the dictionary for ROOT in the compilation process.

Makefile

The Makefile should look like this:

# =============================== 
# Makefile for ana 
# =============================== 

ROOTGLIBS     = $(shell $(ROOTSYS)/bin/root-config --glibs)
ROOTCFLAGS    = $(shell $(ROOTSYS)/bin/root-config --cflags) 

CXX           = g++ 
CXXFLAGS      = -g -Wall -fPIC   	
SOFLAGS       = -shared 

CXXFLAGS     += $(ROOTCFLAGS) 

ANACLASSES = ana.o anaDict.o 

# =============================== 
ana: ana.cc 
# ------------------------------- 
	$(CXX) $(CXXFLAGS) -c ana.cc -o ana.o  
	$(ROOTSYS)/bin/rootcint  -f anaDict.cc -c ana.hh 
	$(CXX) $(CXXFLAGS) -c anaDict.cc -o anaDict.o 	
	$(CXX) $(SOFLAGS) $(ANACLASSES) -o libAnaClasses.so $(ROOTGLIBS) 

# =============================== 
clean: 
	rm -f ana.o anaDict.o anaDict.cc anaDict.h libAnaClasses.so 
# =============================== 

Some Notes

  • When doing copy & paste: Don't forget to replace the leading whitespaces with a tab.
  • After typing make in your directory, you should have five new files: ana.o, anaDict.cc, anaDict.h, anaDict.o and libAnaClasses.so.
  • I don't know anything about Makefiles. Any improvement of knowledge about them would therefore be helpful…

Loading the Class in ROOT

  • Start ROOT and type .L libAnaClasses.so . You can write a Logon script for ROOT that will do this for you.
  • Create an instance of your object. Type ana myanaclass.
  • Execute the method. Type myanaclass.test(). Now you should have successfully created a ROOT file named bla.root.

Troubleshooting

  • Always compile and run the class on the same machine. Otherwise you may get problems with different ROOT versions, different architectures (32- vs. 64-bit), etc.
  • If your code compiles correctly, but you get errors like symbol lookup error … undefined symbol: _ZN5TFile4OpenEPKcS1_S1_ii, this may have several reasons:
    • Check if $ROOTSYS is set (echo $ROOTSYS) and if yes, check if the path of ROOT is the same as in $LD_LIBRARY_PATH and $PATH. If you have setup Gaudi and DaVinci, these things should be correct. Otherwise you have to add
      setenv ROOTSYS /afs/cern.ch/sw/lcg/external/root/5.18.00d/slc4_amd64_gcc34/root 

      (depends on your preferred ROOT version and on your architecture) and

      setenv LD_LIBRARY_PATH $ROOTSYS/lib:$LD_LIBRARY_PATH
      setenv PATH $ROOTSYS/bin:$PATH

      in your .tcshrc file (if you are working on a tcsh).

    • Did you think of the constructor / destructor? A missing constructor may give similar error messages.
    • There may be also be something missing in the Makefile, meaning that not everything is linked correctly.
    • Note: For RooFit you need an additional -lRooFit for the GLIBS
  • The described procedure works for me on lxplus and locally (leopard.physik.uzh.ch).

The original articles about the addition of a class to ROOT are provided here.

root/addclasstoroot.txt · Last modified: 2011/03/08 12:42 by decianm