Adding a class: hand holding requested

Hi,

I have asked this question before here:

https://root-forum.cern.ch/t/adding-a-vector-of-vectors-to-a-tree/11345/1

and have also been pointed towards the documentation for adding a class, but I am still having trouble understanding exactly what I must do.

I am using Geant4 and I want to store output in a TTree. I want to know how to do this for

  1. some class MyClass
  2. some standard library template class like std::vector< std::vector< double > > or even vector< vector< MyClass > >.

For case 1: MyClass,
a. does myClass /have/ to derive from TObject?
b. does myClass /have/ to use the ClassDef and ClassImp macros?

if either of these are true, what can I do in the case that I cannot edit the class code or change the object hierarchy, such as in the case of built in Geant4 classes like G4ThreeVector etc?

c. Is the process for generating the dictionary to run this command?

rootcint -f MyClassDictionary.cc -c MyClass.h MyLibraryLinkDef.h

where MyLibraryLinkDef.h contains:

#pragma link C++ class MyClass+

This generates MyClassDictionary.cc and MyClassDictionary.h

What do we do in the case of MyClass being in a namespace like MyNamespace::MyClass ?

d) What do I do with these files? Do I /have/ to create a shared library with them? If so, what is the exact process for doing that? Where do I need to include MyClassDictionary.h in my program if at all?

for case 2: some standard library container or nested container
a) how is the process different from MyClass?

If anyone could take the time to handhold me through a simple example of getting this to work without using the root command line (I am compiling a geant4 executable) I would be very very grateful. I know the documentation shows an example with Event and Track, but I just haven’t been able to get anything to work.

Thank you.

On Linux, try (for MacOS and/or Windows, you need to find someone who can “transform” the commands given below):

`root-config --cxx --cflags` -fPIC -c MyClass.cxx rootcint -f MyClass_Dict.cxx -c -p MyClass.hxx MyClass_LinkDef.h `root-config --cxx --cflags` -fPIC -c MyClass_Dict.cxx `root-config --cxx --cflags` -fPIC -shared -o libMyClass.so MyClass.o MyClass_Dict.o
The easiest way to try it is:

root [0] .L libMyClass.so root [1] .Class MySpace::MyClass1 root [2] .Class std::vector< MySpace::MyClass1 > root [3] .Class std::vector< std::vector< MySpace::MyClass1 > >
See also [url]Simple way to create and merge shared libraries? for some additional neat Philippe’s notes concerning “ClassDef” / “ClassImp” / “TObject inheritance”.
MyClass.hxx (533 Bytes)
MyClass.cxx (235 Bytes)
MyClass_LinkDef.h (991 Bytes)

[quote]a. does myClass /have/ to derive from TObject?
b. does myClass /have/ to use the ClassDef and ClassImp macros?
[/quote]No neither are compulsory (but both are a performance improvement) See the link Pepe pointed to for more details.

[quote]c. Is the process for generating the dictionary to run this command?[/quote]Yes.

[quote]d) What do I do with these files? Do I /have/ to create a shared library with them?[/quote]Yes (see Pepe’s answer for details)

[quote]a) how is the process different from MyClass?[/quote]It is technically not different. However newer version of ROOT are capable of auto generating those dictionary and libraries.

Cheers,
Philippe.

Pepe, Philippe, thank you for the detailed help!

I am going to try this. But while I’m working I’d like to ask a few more questions:

What is the difference between creating a shared library and just compiling and linking the resulting dictionary files with my executable? By this I mean compiling MyClass_Dict.h and MyClass_Dict.cxx files with the rest of my source and header files. I’m guessing root-config does something important?

Where do I use the shared library? I mean, I know it needs to be linked when I compile my executable, but surely I need to #include the library’s header somewhere in my program, right? (I’m assuming this header in Pepe’s example is MyClass_Dict.h)

If root can auto generate the dictionaries for STL classes, why can’t it auto generate the dictionary for any old class you want to store. I assume you are talking about the fact that I can store a std::vector in a TTree without doing any of this dictionary stuff.

Thank you both, this has been very helpful.

using the files you provided, on the line

`root-config --cxx --cflags` -fPIC -shared -o libMyClass.so MyClass.o MyClass_Dict.o

I get 2119 lines of error. Any idea what’s going on? I’m using Root 5.26/00d, since that’s probably important information.

I will try to play with it with my own classes, but I doubt I’ll have much luck.

EDIT: I can get std::vector< std::vector< double > > to work, but not a custom class I called TestClass. In addition, vector< vector< double > > no longer works if I try to use it and TestClass.

In order to get it to work I just created a dictionary header and source file with rootcint and compiled them with the rest of my sources and headers in my normal build. It was storing vector< vector< double> >, but now, frustratingly, it isn’t working anymore.

Maybe you could try:

If this fails, too … you need to copy here some first lines and some last lines with errors so that we might try to guess what went wrong (the first 20 and the last 20 lines?).

Pepe, that fixed the error and created the library.

So now that I have these files:
MyClass_Dict.h
libMyClass.so

What do I need to do from there? I obviously need to link libMyClass.so with the rest of the libraries in my executable, but what about the header file?

Thanks for the help.

  1. I think that you do not need to create a shared library. You can simply add “MyClass.o” and “MyClass_Dict.o” to the list of objects in the linking stage of your executable (don’t forget to add ROOT related libraries, too). I personally prefer the “shared library approach”, however. Afterwards, I can re-use that library in a standard root session (as shown in my first post here) without any modifications (for example, if you want to read a ROOT file with such objects, written by your application, you will need the dictionary, too).

  2. Add this shared library (together with another ROOT related libraries) to the linking stage of your executable. In the source code of your application use only “MyClass.hxx” (forget about “MyClass_Dict.*” files). For informations about “root-config”, simply type:
    $ root-config --help
    $ man root-config

  3. I believe ROOT knows some “most common” STL related cases (i.e. they are already “precompiled”), but about any “more complex” stuff you need to take care yourself. Try:
    root [0] .Class std::vector< int >
    root [1] .Class std::vector< std::vector< int > >
    root [2] .Class std::vector< double >
    root [3] .Class std::vector< std::vector< double > >

Okay success!

This is not your method Pepe. Maybe you can explain the differences/advantages to your method vs. mine?

EDIT: I can see that you already posted while I was writing this. I haven’t gotten as far as reading the data back out of the root file. Maybe it will be harder without using the shared library as you have indicated?

I created a class TestClass:

TestClass.hh:

[code]class TestClass
{
double x,y,z;
public:
TestClass();

};[/code]

TestClass.cc

[code]#include “TestClass.hh”

TestClass::TestClass()
{
x = 1.0;
y = 2.0;
z = 3.0;
}[/code]

I created a file called Root_LinkDef.h:

[code]#ifdef MAKECINT

#pragma link off all typedefs;
#pragma link off all globals;
#pragma link off all functions;
#pragma link off all classes;

#pragma link C++ class std::vector< std::vector< double > >+;
#pragma link C++ class TestClass+;

#endif[/code]

I ran this command:

and I moved the output files dictionary.cxx and dictionary.h into my src and include directories (I needed to change the extension to .cc to get it to compile with my makefile)

cp dictionary.cxx src/dictionary.cc cp dictionary.h include/

and then I just created a branch for a TestClass object and a branch for a vector<vector> and stored them in a TTree. I didn’t need to #include any headers.

I’d just change “.cxx” into “.cc” directly here … and learn the “-p” flag … you will often need it …
rootcint -f dictionary.cc -c -p TestClass.hh Root_LinkDef.h

Also, as you plan to use “std:: vector”, maybe it would be good to:
#include
in your “TestClass.hh” file.

One more thing. If you ever use “ClassDef”, remember that it must be the last line in your class definition AND it must be PUBLIC:

class MyClass { public: // something protected: // something else private: // yet something else public: ClassDef(MyClass, 1); // My Class title };

what does -p do? or -f for that matter? man rootcint doesn’t list the meanings of any of the flags.

I was also confused by your use of root-config .... I’m not sure what root-config actually does. The description makes it sound like it has something with generating makefile lines, but I have to be misunderstanding. I guess that you are using the result of root-config to add the other flags like -fPIC, but I don’t really understand what’s going on or to what program the -fPIC flag belongs (or what it means). I don’t feel like the sharpest tool in the shed!

Thanks for all the help so far. It seems like a simple process now that it is working, but in reality it has been very difficult for me to get right.

I’m sure I’ll have more issues once I try to read things back out.

Try to type:
$ root-config --cxx --cflags
$ root-config --glibs

For “rootcint” flags, type:
$ rootcint -h
$ man rootcint
See also “man makecint” and http://root.cern.ch/viewvc/trunk/cint/doc/makecint.txt

For “-fPIC” and “-shared” flags (and another g++ related flags), type:
$ man g++
$ info g++