Base class has no streamer or dictionary


_ROOT Version: 6.24/07
_Platform: CentOS 7
_Compiler: gcc version 10.3.0 (GCC)


We are trying to understand why we get the error message

“ap_int_base<36,false>: base class ssdm_int_sim<36,false> has no streamer or dictionary it will not be saved”
when we try to save our custom classes to file.

 Background:  We are developing FPGA code for the CMS trigger, using

Vitis HLS (High Level Synthesis) which, in theory, allows the same C++ code
to create the FPGA payload and also to simulate the result within the CMSSW
framework. We use headers for arbitrary-precision integers provided by Xilinx:
GitHub - Xilinx/HLS_arbitrary_Precision_Types with a “local” copy at
/cvmfs/cms.cern.ch/slc7_amd64_gcc10/external/hls/2019.08-80454731218d87c9edf8f512cb8429f9/include

The error given above puzzles us, because while it's true that class

ssdm_int_sim does not have streamers (by which I understand overloads for
stream operators >> and <<, to allow serialisation/deserialisation) the
derived class ap_int_base does, e.g.

INLINE std::ostream& operator<<(std::ostream& os,
const ap_int_base<_AP_W, _AP_S>& x) {
std::ios_base::fmtflags ff = std::cout.flags();
if (ff & std::cout.hex) {
os << x.to_string(16); // don’t print sign
} else if (ff & std::cout.oct) {
os << x.to_string(8); // don’t print sign
} else {
os << x.to_string(10);
}
return os;
}

These overloads do seem to work on "normal" code, viz.

[eesridr:test] > cat test2.cc
#include
#include
#include “ap_int.h”

int main() {

ap_int<36> A{255}, B{0};
ap_int_base<36, false> C{1000}, D{0};

std::ofstream ofs;
ofs.open (“testout.bin”, std::ofstream::out | std::ofstream::trunc);

ofs << A << " " << C;
ofs.close();

std::ifstream ifs;
ifs.open (“testout.bin”, std::ifstream::in );
ifs >> B >> D;
ifs.close();

std::cout << B <<" “<< D <<”\n";

return 0;
}

[eesridr:test] > g++ -I/cvmfs/cms.cern.ch/slc7_amd64_gcc10/external/hls/2019.08-80454731218d87c9edf8f512cb8429f9/include testh.cc
[eesridr:test] > ./a.out
255 1000

 So, why does this not work in ROOT?  Why does it look to the base class

for the streamers?

Thanks,
	ivan

ROOT does not use those for serialization (for example they would not support splitting in independent column nor automatic schema evolution). Instead we use the C++ introspection provided by Cling (leveraging clang).

In the CMSSW context, to generate dictionary you need to have a selection.xml and update the build system to request its use for building.

@pcanal In the CMSSW context, to generate dictionary you need to have a selection.xml and update the build system to request its use for building.

OK, it turns out we do have a classes.h and a classes_def.xml, and build a dictionary /tmp/L1TriggerDataFormats_TrackFindingTrackletHLS_xr.cc when compiling. This includes three classes that I had to add to the .xml file to remove original errors:

grep 'ap_' /tmp/L1TriggerDataFormats_TrackFindingTrackletHLS_xr.cc | grep namespace
} // end of namespace ROOT for class ::ap_uint<36>
} // end of namespace ROOT for class ::ap_uint<7>
} // end of namespace ROOT for class ::ap_private<36,false,true>

So this still leaves the question of why it wants a dictionary for class ssdm_int_sim<36,false>, or how we force compilation to build it.

The original message indicates that one is try to store (directly or indirectly) an object of type ap_int_base<36,false> in a ROOT file. In order to store that kind of object, ROOT needs to know about each of its components so that it can store those as part of the ap_int_base<36,false> object. The error message indicates that the base class ssdm_int_sim<36,false> is one of those components and thus needs a dictionary.

Thanks. Your message prompted me to review our build process. I’d gone off on a tangent when adding ssdm_int_sim<36,false> led to segment failure. When I added ap_int_base<36,false> as well, the segfail went away, and I was then able to iterate execution finding each of several other classes that needed to be added to classes_def.xml until there were no more failures. Now I’m able to save the objects from the second of three steps, and successfully run just the third step on the resultant file. Thanks again for leading me back down the correct rabbit-hole.