Making TFileMerger Compatible Classes

Hello,

I’m trying to write a class that can be merged with TFileMerger. I’m using ClassImp and ClassDef as described in the documentation and inheriting from TNamed. File input and output is working fine so I don’t think that there’s a problem with those parts. I can also tell what I need to add to handle the merging from the TFileMerger code. Where there is an issue is where TFileMerger casts the returned pointer to my class as a TKey* and tries to call GetClassName(). The value for fClassName isn’t set automatically and if I try to inherit from TKey and set it from within my class I get a segfault. How am I supposed to define a value for the class name?

Thanks

Alright, so this turned out to be one of those situations where cint segfaults and it works fine with aclic :-/. Inheriting from TKey and setting fClassName stores the class name properly. If I then open the file in cint (without manually loading the class header or associated shared object) and look at the relevant key then GetClassName() returns the correct value and TClass::GetClass(key->GetClassName()->InheritsFrom(TObject::Class()) returns true. When I try running hadd on the other hand I get one warning about the dictionary not being available for the class and then each corresponding key fails this check in the TFileMerger code. In this code key->GetName() and key->GetTitle() both return “”.

TClass *cl = TClass::GetClass(key->GetClassName()); if (!cl || !cl->InheritsFrom(TObject::Class())) { Info("MergeRecursive", "cannot merge object type, name: %s title: %s", key->GetName(), key->GetTitle()); continue; }

So, I’m guessing the issue here is something to do with either linking the dictionary or the shared object. Anyone have any insight here? I’m surprised at how little information is out there about merging root files with custom classes in them.

Hi,

Classes that are not compiled (via ACLiC or via rootcint + compiler) are not support in I/O (and thus not by the TFileMerger).

[quote]Inheriting from TKey and setting fClassName stores the class name properly. [/quote]Unless you have a very unusual use case, your object should NOT inherit from TKey.

The way things works is that you stored on object via:

mydirectory->WriteObject(objptr,"name");which streams your object into a memory buffer, create a TKey with the right information (name,classname) and write the 2 in the file.
while mydirectory->GetObject("name",objptr);will do the reverse.

I.e. you should not have to deal directly with the TKey.

To add support for merging your object via TFileMerge instead you need to implement either:virtual Long64_t Merge(TCollection *list);or virtual Long64_t Merge(TCollection* list, TFileMergeInfo *info);See TH1::Merge and TTree::Merge for example.

Cheers,
Philippe.

Hi Philippe,

Thanks for the help! I didn’t realize that I needed to be compiling until I had made the switch to inheriting from TKey. I switched it back to TObject and compiled it, but it’s not quite working yet. If I step through getting the key from the file in cint then InheritsFrom(TObject::Class()) returns true and GetClassName() returns the proper value but if I use hadd I get the following:

[quote]Target file: merged.root
Source file 1: file1.root
Warning in TClass::TClass: no dictionary for class CustomClass is available
Source file 2: file2.root
Target path: merged.root:/
Cannot merge object type, name: TObject title: Basic ROOT object[/quote]

This means that in hadd InheritsFrom(TObject::Class()) is returning false? Also shouldn’t the name match the one I set with WriteObject(objptr, “name”)? If I instead inherit from TNamed then GetClassName() returns “TNamed” in cint and presumably in hadd as well. This then causes problems when hadd tries to read the objects out:

Do I need to make the dictionary for the class available to hadd in some way?

Hi,

[quote]This means that in hadd InheritsFrom(TObject::Class()) is returning false?[/quote]No, it is still returning true but it does not find/see the Merge function.

[quote]If I instead inherit from TNamed then GetClassName() returns “TNamed” in cint
[/quote]This should happen only if you did not compile (and generate the dictionary for) your class.

[quote]Do I need to make the dictionary for the class available to hadd in some way?[/quote]Yes you do. You can do so my enabling the autoloading of your class’ library by creating a rootmap file.

If you have a linkdef file you can use (assuming you library is named libMyClass.so):rlibmap -f -o libMyClass.rootmap -l libMyClass.so -c linkdef.hIf you are creating the class with ACLiC you can do:

gEnv->SetValue("ACLiC.LinkLibs",3); .L MyClass.cxx+and the directory in which you create the library must be in the LD_LIBRARY_PATH.

Cheers,
Philippe.