Dictionary usage for writing std::vectors into TTree

Hi,

I would like to store STL vectors containing Bool_t, ULong64_t and Double_t variables as well as strings into a ROOT tree by using a self-written executable compiled with g++. For this, I have created a dictionary based on the instructions in the FAQ on how to embed dictionary creation into a makefile.

Due to some problems arising when doing this, I have the following questions:

[ol]
[li] When linking the library the “proper” way (compiling the source generated by rootcling into an .so shared library), I get error messages like these for every branch containing an STL vector:

Error in <TTree::Branch>: The class requested (vector<long double>) for the branch "pkHeightSum" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (vector<long double>) to avoid to write corrupted data.
The dictionary library has been linked against by passing “-L$(LIBDIR) -lRootDict” to g++ when linking the executable, with “$(LIBDIR)” being the path to the directory the library is in and “libRootDict.so” being the name of the created dictionary library. Moving the library and its .pcm file into a directory specified in /etc/ld.so.conf does not resolve the issue, and deleting both does not produce an error message saying that a library could not be found. How does an example compiler command for proper linkage look like?[/li]
[li] Is it possible to simply compile the dictionary source file generated by rootcling into an object file and then link it into the final executable, or would this cause undefined behavior? Currently, when I am doing it this way, the executable complains about the dictionary’s .pcm file not being found, but otherwise it does at least not print any errors (if I recall correctly, the .pcm files are currently not used anyway, but this might of cause induce problems in the future). If this approach is valid: Is there a way to suppress .pcm-related error messages? Or is it possible to “link” the .pcm into the executable or to specify the path to it?[/li]
[li] For an older tree generator which I had built with ROOT 5.34, using a similar approach as described in 2.) to directly link the dictionary into the executable, warnings were shown when an event had empty vectors stored (this was some months ago and I do not, at the time, have the source files for it on my current computer, so I cannot give you the precise warning messages) . Is there a “proper” way to save empty vectors besides filling in dummy values?[/li]
[li] Is there a way to guarantee portability of .root files with trees containing STL vectors, i.e. is it possible to read a .root file containing such a tree on a computer with an architecture different to the computer the tree was generated with without getting bogus/corrupted values? [/li][/ol]

[u]Specifications:[/u]
OS: Linux Mint 17.1
Kernel: 3.13.0-37
g++ version: 4.8.2
ROOT version: 6.03/03

Linkdef.h (based on an automatically generated Linkdef.h; some lines commented out due to rootcling warnings which tell that aforementioned lines are ignored anyway when they are uncommented):

#include "Rtypes.h" #include "vector" #ifdef __CINT__ #pragma link C++ nestedclasses; #pragma link C++ nestedtypedefs; #pragma link C++ class string+; //#pragma link C++ class string::*; #pragma link C++ class vector<Bool_t>+; //#pragma link C++ class vector<Bool_t>::*; #pragma link C++ class vector<ULong64_t>+; //#pragma link C++ class vector<ULong64_t>::*; #pragma link C++ class vector<Double_t>+; //#pragma link C++ class vector<Double_t>::*; #pragma link C++ class vector<vector<ULong64_t>>+; //#pragma link C++ class vector<vector<ULong64_t>>::*; #pragma link C++ class vector<vector<Double_t>>+; //#pragma link C++ class vector<vector<Double_t>>::*; #ifdef G__VECTOR_HAS_CLASS_ITERATOR #pragma link C++ operators string::iterator; #pragma link C++ operators string::const_iterator; #pragma link C++ operators string::reverse_iterator; #pragma link C++ operators vector<Bool_t>::iterator; #pragma link C++ operators vector<Bool_t>::const_iterator; #pragma link C++ operators vector<Bool_t>::reverse_iterator; #pragma link C++ operators vector<ULong64_t>::iterator; #pragma link C++ operators vector<ULong64_t>::const_iterator; #pragma link C++ operators vector<ULong64_t>::reverse_iterator; #pragma link C++ operators vector<Double_t>::iterator; #pragma link C++ operators vector<Double_t>::const_iterator; #pragma link C++ operators vector<Double_t>::reverse_iterator; #pragma link C++ operators vector<vector<ULong64_t>>::iterator; #pragma link C++ operators vector<vector<ULong64_t>>::const_iterator; #pragma link C++ operators vector<vector<ULong64_t>>::reverse_iterator; #pragma link C++ operators vector<vector<Double_t>>::iterator; #pragma link C++ operators vector<vector<Double_t>>::const_iterator; #pragma link C++ operators vector<vector<Double_t>>::reverse_iterator; #endif #endif

Hi,

thanks for the complete post. My answrers in steps.

  1. This should not happen: can you confirm that the libraries are actually linked to the executable? Are you using rootmaps? As far long double is concerned, ROOT IO does not support this type.
  2. The pcm files are in use. They should be located next to the binary which contains the dictionary they refer to.
  3. I think a reproducer for this would be needed. It is hard to diagnose the problem from the description :frowning:
  4. The cross platform portability is one of the most powerful features of ROOT and is guaranteed. What file aren’t you able to re-read? What are the platforms involved?

Cheers,
Danilo

@Danilo:
Thank you for your answer. Regarding your points:

1.) I have placed the linking directives for linking against the generated library ("-L$(LIBDIR) -lRootDict") at the very end of the compiler command for linking the executable (before, it was in front of the ROOT library linking directives) and put the path which includes the generated library and its pcm file into my ld.so.conf. It seems to work properly now. :smiley:

2.) This has resolved itself after having solved 1.).

3.) If I encounter this problem again, I will open a new thread here.

4.) I once had error messages regarding vector branches not being readable when opening TTree files on a PC with ROOT V5.34 (x86) which have been generated with ROOT V5.26 on an x86_64 PC. As with 3.), I will return here if I encounter this problem again.

Hi Dom,

1/2) Great news!
3/4) Sure: feedback is always most welcome.

Cheers,
Danilo

I’m having the same problem, but since I’m no expert and new on this, I wonder what does step 1) really means.

I use a cmake file to compile my program and it looks like this:

cmake_minimum_required(VERSION 2.8)

project(FibersAna)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -std=c++11 -fPIC")

find_package(ROOT REQUIRED COMPONENTS Core Hist Gui Graf Graf3d Gpad Tree)
if(ROOT_FOUND)
    message(STATUS "ROOT found: ${ROOT_FOUND}")
    message(STATUS "ROOT_CXX_FLAGS: ${ROOT_CXX_FLAGS}")
    message(STATUS "ROOT_INCLUDE_DIRS: ${ROOT_INCLUDE_DIRS}")
    message(STATUS "ROOT_INCLUDE_DIRS: ${ROOT_INCLUDE_DIRS}")
    message(STATUS "ROOT_LIBRARIES: ${ROOT_LIBRARIES}")
    message(STATUS "ROOT_DEFINITIONS: ${ROOT_DEFINITIONS}")
    message(STATUS "ROOT_LIBRARIES: ${ROOT_LIBRARIES}")
    include(${ROOT_USE_FILE})
    include_directories(${ROOT_INCLUDE_DIRS})
    INCLUDE(${ROOT_DIR}/modules/RootNewMacros.cmake)
endif()

set (CURRENT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR})


set(HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/functions.h ${CMAKE_CURRENT_SOURCE_DIR}/DataStruct.h ${CMAKE_CURRENT_SOURCE_DIR}/definitions.h)

add_executable(ReadBinary drs_bin2root.cpp ${HEADERS})

target_link_libraries(ReadBinary Spectrum ${ROOT_LIBRARIES})

Where do I have to add this ("-L$(LIBDIR) -lRootDict")? in a macOS 10.12.16 the procedure is the same as in a Linux OS?

ROOT version is 6.08.04.

Thank you in advance

1 Like