Previous PagePrevious Page
ROOT Cint 48
  • 01 Feb 2012 23:50:09

For various reasons, one may wish to compile a ROOT macro with something other than CINT, the default interpreter of ROOT.

If you want to trust the scientific validity of your results, you better know there weren't any memory leaks in your analysis! Apparently it is possible to use valgrind within ROOT using the PROOF call, although you'd need to make sure ROOT was built with --build-debug. See the ROOT website under Running the PROOF query in valgrind

General criticism of CINT

Please keep in mind that I am not very knowledgeable about many of these details, and I am not an expert of C++. I also have a lot of respect for the work done to create ROOT, and the many useful features it offers. However, it doesn't mean my experience is entirely positive, and I want to shed light on some of these topics for others with a similar line of thought to me, for a better programming and data analysis experience.

Practically speaking, if you are doing either complex data analysis (lots of looping or polynomial solving, for instance) and/or using very large data sets (think gigabytes or terabytes), you will start to care about execution speed. You can choose a benchmark which is most closely like the kind of programming you are doing, but CINT is attrociously two to three ORDERS OF MAGNITUDE slower than gcc compiled code. We're talking about in some caess the difference of running a program in 20 seconds compared to 20 hours. Go enjoy some benchmarks. Very strangely, ROOT's official website on CINT references the very same Benchmarks Game website for CINT at the very bottom under 'a few random pointers.' I wouldn't think a logarithmic plot showing time and memory usage differences with gcc was something to be referenced in a casual offhand sort of way, but I guess this is their thinking!! The Benchmarks Game is also using C and not C++ code.

CINT is a tough method for data analysis. One advantage of C++ is its speed. The disadvantage is that it's a very difficult language to learn and program in, by almost all accounts. So if we interpret C++ code, we get the worst of both worlds. We get to try to script in an obtuse language not designed for scripting, and it is slower than a herd of pregnant turtles.

Of course, ROOT is having CINT compile your macro before running it usually (by ACLiC), so I'm not really sure where it would fall under these benchmarks. But my personal experience says that, anyway, running stuff under ROOT's CINT is certainly slower than compiling it instead with gcc, but I don't think it was 2 orders of magnitude difference. Here I am showing you the method to use the rootcint program with gcc, which is in some sense just basically the same ROOT is using to convert the class structures and compile the code, so I guess this webpage won't help you get too much more juice out of your analysis. Better to entirely re-write the class structure and use ROOT only as a library, but that's a lot of work! Anyway, the resulting dictionary files I'll help you to make will end up being even larger than the original code in terms of the number of codelines and filesize.

There can be other ways of avoiding CINT as well (in one way or another), which I won't discuss on this page. My personal solution will be to help build the SciRuby system and not use ROOT for data analysis after my PhD. If you want something that's already functional, you can have a look at SciPy and try to wind this up with PyROOT. If you want some fancier framework besides the command line, you could give QtROOT a whirl.

My reasons for avoiding CINT

Anyway, this page doesn't help as much with those general problems. But it will help with some other problems I wanted to avoid myself.

Debugging ROOT macros with CINT is hell. If you compile the code with gcc, you may get useful compiler outputs for bugs instead of straight segmentation faults from ACLiC.

If you make an executable, you can do a lot more with it. Like running the GNU Debugger on it.

To further this, you can even then use a memory debugger like Valgrind on your subsequent code, to help remove sneaky bugs. Uninitialized variables, for example, are not caught by ROOT, or even gcc usually. So please do this, whether by my method, or using ROOT's PROOF query (linked at the top).

CINT also does not conform to ANSI C++, so this way you can write real C++ code. You should think of ROOT as a set of physics libraries for C++, not a language or a compiler. Although CINT is doing some compiling of code, it's really an interpreter, making your C++ into something closer to a scripting language than a compiled language.

Like most interpreted languages, basically any errors just occur and crash the program without a hint as to why. Bluntly put, when you have bugs in your ROOT code, probably CINT/ACLiC will just give you a segmentation fault, where as using gcc on the (basically same) code is much more helpful for debugging. (CINT is great for interacting with the results of a program once I've compiled and executed it, but not beforehand.)

Compiled languages will usually be statically typed (a nice discussion here) and the compiler will check your code for errors before runtime, which can be helpful. And by helpful I mean it will keep zombies from trying to eat your brain or eyes.

Getting started

I found the available documentation quite lacking (after all, this is not the officially supported method, so why can you expect much upstream help?), but I was able to compose a successful Makefile for a set of ROOT macros with multiple layers of class inheritence and implementations as well as cross compile with a Fortran subroutine. In order to achieve this result, besides local files, I referenced only the Cint Generator page (please note, last update 1997) and a particular email archive addressing LinkDef.h from 2002.

This is rather astounding to me, given the extreme slowness of CINT compared to C++ compiled code, and the presumably huge data sets and complex analysis being done at the LHC.

Thus, if you want to compile ROOT Macros outside CINT, say with g++, then perhaps you can get some basically useful information here.

I got this idea from Andy Buckley's article on basic ROOT usage, although I should note, his commands to avoid Cint are erroneously missing backticks, and should read as:

g++ -c `root-config --cflags` *.cpp
g++ -o mkBuVarPlots `root-config --libs --cflags` Bu2KsPi-selection-plots.cpp SBHisto

While this might get you on the right track, as it did for me awhile back, it's just the beginning of how you can entirely avoid CINT for the rest of your (now less) miserable life.

Another useful resource may be the HEP wiki of Simon Fraser Univsersity.

Disclaimer — these Makefiles are for Linux!

Below I'll give some basic details how you might understand how to port these Makefiles to another operating system, but don't email me questions asking how to write Makefiles for something other than Linux. Most of those systems I don't have access to and maybe never even used.

I provide this documentation because I had to do all the work for myself anyway, and I work in Linux. So, if it has any value outside Linux, I have no clue.

Quick Makefile for stand-alone simple ROOT macros

Of course Andy's above example, when done with backticks, works just fine. But I'm pretty lazy, and if you're reading my website, you must be even lazier than me for not figuring it out yourself.

Thus, I provide a sample Makefile and a crappy test.C macro for you enjoyment and amusement. Download them somewhere and

$ make
$ ./test

and there you have a functional ROOT macro as an executable. Of course there isn't a whole lot of reason to compile such a simple and useless program as that, but maybe someone will learn something from it.

A Makefile for class structures

You can find a more updated and complex version of the example software here now hosted by me at GitHub. The Makefile there is a lot better, for instance.

If you have anything more than a single ROOT macro, or particularly if you have any classes at all you will need to use rootcint. Sorry, it's not my fault ROOT's main page on the subject is just a copy of the man pages. I get the feeling I might be the only person in the whole world with almost any interest to do this kind of thing; either that or I'm the only person who can't magically make my computer do whatever I want without reading any manuals, 'cause the official documentation is awful.

People like to say 'RTFM' (you know, read the 'fine' manual), but in this case, BTFM I say (just burn it).

rootcint is apparently part of the ROOT Development Kit (RDK). For Gentoo Linux, this is already installed from portage. For other flavors of Linux, if you can't find rootcint on your machine, I guess you should do a google search on to find out how to install it. Don't ask me, I don't know.

If you don't use rootcint to handle the classes, you'll probably start to get errors like the following:

daid@flux ~/active/testrootless % make
g++ -c `root-config --cflags` test.C
g++ -o test `root-config --libs` `root-config --cflags` test.C
/tmp/ccBZrWsO.o: In function `__static_initialization_and_destruction_0(int, int)':
test.C:(.text+0x39ae): undefined reference to `ROOT::GenerateInitInstance(TArtFadcHit const*)'
collect2: ld returned 1 exit status
make: *** [test] Error 1

See that GenerateInitInstance error? That's not really in my code, it's basically a linking error. You need to use rootcint to get around this stuff, which is a fabulously wonderful tool for anyone who wants or needs to avoid CINT.

If you want some idea what to do, it's best to try an example. Download anarootcint.tar.gz.

Now this code is not really simple, but you don't need to care about the code details, just the structure.

Rather than doing what the main ROOT site says, which is making a main.C something standard like:

void ana2()
//do stuff

What I suggest to do is make the top-level macro into a main function. The reason for this, in my example, is that ana3.C wants user input initially, which is skipped if you open a new ROOT session. Later on, when I compile this crap by adding in a Fortran subroutine, and later KaliVeda libraries, I'll add the nice parts of this main.C to the end of my ana3.C so it opens an interactive ROOT session after ana3.C has otherwise finished!

To turn the top-level macro (whatever you'd call first in ROOT) into a main macro, all you really need to do is change it's namesake function into a main function (int, not void) and then toss a return(0); at the end. In my example you can see I just commented it out and made a new one:

#include "TROOT.h"
#include "TRint.h"

int main(int argc, char **argv)
// do stuff

// Create interactive interface
TRint *theApp = new TRint("ROOT example", &argc, argv, NULL, 0);

// Run interactive interface


In the future, I'll set up some kind of #ifndef __CINT__ check for which way to call the code (edit: this is now done in crabat code linked above at GitHub), but for now, I'm presuming I've forsaken CINT for this codeset and will be command-line compiling in the future.

And any other return; you have needs to also be return(0); otherwise you'll get stuff like:

daid@flux ~/active/anarootcint % make clean;make
Generating Calibration dictionary ...
g++ -Wall -fPIC `root-config --cflags` -c -o dictCal.o dictCal.C
Generating Analyzer2 dictionary ...
g++ -Wall -fPIC `root-config --cflags` -c -o dictAnaly.o dictAnaly.C
g++ -Wall -fPIC `root-config --cflags` -c -o ana3.o ana3.C
In file included from ana3.C:2:
Analyzer2.C: In member function ‘virtual void Analyzer2::Loop()’:
Analyzer2.C:208: warning: unused variable ‘gate_29p’
Analyzer2.C:165: warning: unused variable ‘ppac_calib’
ana3.C: In function ‘int main()’:
ana3.C:84: error: return-statement with no value, in function returning ‘int’
make: *** [ana3.o] Error 1

Any stuff you want to load as a shared object in CINT, like


is better to comment out and just include at the beginning (or in a header file, whatever):

#include "Analyzer2.C"

For my example, though I don't use an ana3.h (would be main.h) since I didn't want to add any extra things to complicate compiling my existing ROOT macros.

Great, so now you understand all the actual changes I made to my code, besides maybe adding some very basic libraries like stdio and other fun stuff wherever the compile errors came up. (Note: I probably have a lot of nested includes in a way that is not at all optimized. For now, I was happy to get code that compiles and runs.)

So now you should understand the inheritence structure.
  • ana3.C includes Analyzer2.C

  • Analyzer2.C includes Analyzer2.h and Calibration.C

  • Calibration.C includes Calibration.h

So we have a multi-layer inheritence structure.

For each header code with classes, you should make a corresponding linkdefGoatface.h file for rootcint.

For my example, Analyzer2.h has two classes, Analyzer2 and TArtFadcHit, so:

daid@flux ~/active/anarootcint % more linkdefAnaly.h
#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link off all typedef;
#pragma link C++ class Analyzer2;
#pragma link C++ class TArtFadcHit;

and Calibration.h has one class, just Calibration:

daid@flux ~/active/anarootcint % more linkdefCal.h
#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link off all typedef;
#pragma link C++ class Calibration;

At this point, the code should basically compile if you've written a sane Makefile. My Makefile should already work with my example, but if you wanted to use this example to do your own code, you should understand what's going on here.

If you are on a different platform, you might get some hints how to change your Makefile from the ROOT Makefile.arch which may or maynot already be installed on your system. For Gentoo Linux, this was default until ROOT v.5.22 and then one needed the USE flag "examples"

For Gentoo, this file is at /usr/share/doc/root-5.26.00-r4/examples/Makefile.arch which I suggest searching for your ARCH. This is about as much help as I can offer for other architetures in terms of Makefiles. However, a lot of the structure, like the rootcint calls, are going to be just the same as in Linux, as long as you know what to pass to your compiler (and I hope the name of your compiler).

The first thing that has to happen is to make the dictionaries for the codesets with classes via rootcint. Since Calibration.C is the lowest on the dependency hierarchy (it inherets from nothing else locally), then I do that first. Two things are done. Number 1 is I make it the first OBJECT I want to compile:

OBJS = dictCal.o dictAnaly.o ana3.o

Please note that since the make utility will auto-resolve basic dependencies, the actual ordered sequence of the objects ought not to matter. It also doesn't matter that dictCal.C doesn't exist, because we will write a rule within the Makefile to do just that:

dictCal.C: Calibration.h
      @echo "Generating Calibration dictionary ..."
      @rootcint dictCal.C -c Calibration.h linkdefCal.h

(Warning: You cannot copy/paste HTML text for Makefiles because HTML condenses tab as whitespace)
The @ symbols mean it's not going to print the command itself, only the results of the command. If you want the command itself printed to the screen as you make, get rid of them.

There are basically two important points here. The first is that whatever name you make for your dictionary for one file needs to be consistent in the Makefile. Secondly, the correspoding LinkDef.h file must be the last file in the rootcint call.

So once you understand what I did to make the dictionary for the Calibration.h class, it's easy enough to see that I do the same thing for things in Analyzer2.h

Once these dictionary rules are finished in the Makefile, it's just a matter to tell it the name of your main program (here ana3) under both the OBJECTS and the PROGRAM.

And that's it. Now you can understand how to make your own compiling ROOT macros. In case you didn't realize, the output is ana3 so you can easily run it:

daid@flux ~/active/anarootcint % ./ana3
Existing runs are:
../root/alpha-calib-post1011.root ../root/ssd-pulser-post1005.root ../root/ssd-pulser-post1010.root ../root/ssd-pulser-post1015.root ../root/ssd-pulser-post1020.root
../root/ssd-pulser-post1001.root ../root/ssd-pulser-post1006.root ../root/ssd-pulser-post1011.root ../root/ssd-pulser-post1016.root ../root/ssd-pulser-post1021.root
../root/ssd-pulser-post1002.root ../root/ssd-pulser-post1007.root ../root/ssd-pulser-post1012.root ../root/ssd-pulser-post1017.root ../root/ssd-pulser-post1022.root
../root/ssd-pulser-post1003.root ../root/ssd-pulser-post1008.root ../root/ssd-pulser-post1013.root ../root/ssd-pulser-post1018.root ../root/ssd-pulser-post1023.root
../root/ssd-pulser-post1004.root ../root/ssd-pulser-post1009.root ../root/ssd-pulser-post1014.root ../root/ssd-pulser-post1019.root

Select a run to be analyzed
(ie: 1 means ../root/alpha-calib-post0001.root
1-10 means processing all of the run 1 to 10):

though since you probably don't have the directory ../root with .root files in it, don't expect it will do much for you.

That should be all you need to know to get a Makefile working to compile ROOT macros outside CINT.

Cross-compiling a ROOT macro with Fortran

It's probably a bad day when you had to both read Fortran code and compile ROOT outside CINT.

(Note: I later found an official page similar to this subject, but it doesn't discuss Makefile creation or compiling code outside CINT. I doubt reading this page would have helped me at all in my work here, but your interests may differ from mine.)

I assume since so many people in physics are still stuck in the stone-age writing Fortran code, you might want to use some of it, because you are lazy like me and don't want to re-write their code in a more sane language. Or you are even lazier still, also like me, and you refuse to actually read Fortran code at all whenever possible, but you still want to use it sometimes.

Anyway, obviously if you are reading this section, you either hate yourself, or you need (or want) to use Fortran subroutines of some kind in conjunction with a ROOT macro. I'll tell you just how to do it!

The first thing I lament to say is that I can only succeed to do this using a KaliVeda library. I've now fixed this in some of my other code, because it was just some headers KaliVeda was including for me that I was too stupid to include myself. I'll update the examples here later...

So, umm, you need to go install KaliVeda first, until I give you a newer example with the bugfix. But in any case, if you study nuclear physics, you will be glad I made you install the KaliVeda libraries, because they are extremely useful. Also, do not ask how I managed to get my Makefile working successfully and find this makes no sense at all.

It will be easier if you use the crabat program I linked to GitHub earlier, since it fixes a lot of these bugs (I only wrote this website like the first time I ever tried to do this...and bugfixing example files for my website isn't my first goal in life).

Start out downloading anarootcintf.tar.gz. You will also need to grab enewz of some kind and compile it for my test case. Yes, I am only making this webpage because I already did this stuff myself, not as a real tutorial. enewz calculates energy loss of ions in matter. It's also wonderful. Once you get KaliVeda installed and have run make on enewz, you need to copy libenewzlib.a into the directory of anarootcintf

Otherwise, this is basically very simple.

You can see that near the top I've modified ana3.C in order to define and call enewzsub2. Otherwise, compared to the above case, all I've done is add the FOBJS and the ARCHIVE items (and a call or two to them) in the Makefile.

Since you had to install KaliVeda anyway for this part, then you can see that those libraries are easily called within this structure, too.

Notes on Valgrind

Until I make a dedicated page on some tricks with Valgrind, I'll just post them here to remind myself (or others)

To debug the error: Conditional jump or move depends on uninitialised value(s), please see this useful note.

To debug the error: Mismatched free() / delete / delete[], please see the section Mismatched Use of Functions. If you're still confused and want an explict example, see the Wikipedia article on the C++ delete function.

There is a suppression file for using Valgrind on ROOT. To quote:

# This file suppresses known and expected / inevitable valgrind
# reports, e.g. due to ROOT's runtime type information that must
# survive until the end of the process and thus leaks.
# It only suppresses leaks, and a few errors generated by X11.

This file is included with root. Supposedly, it is in $ROOTSYS/etc/valgrind-root.supp but that depends on your distribution. For Gentoo it wasn't there, but I found it easily enough where I expected...

        (__)               __(^^)              /   /    (__)      / PhD  \  (oO)     /|  /---^^---/     / | /| daid  ||    *  || ||------||
Next page