2020#include < TH1.h>
2121#include < TError.h>
2222#include < algorithm>
23+ #if defined(_LIBCPP_VERSION)
24+ #include < TList.h>
25+ #include < TStreamerElement.h>
26+ #include < TStreamerInfo.h>
27+ #endif
2328
2429namespace o2 ::framework
2530{
@@ -31,6 +36,9 @@ void* extractFromTFile(TFile& file, TClass const* cl, const char* what)
3136 if (!cl) {
3237 return nullptr ;
3338 }
39+ #if defined(_LIBCPP_VERSION)
40+ DataRefUtils::registerLibstdcxxStdArray (file, cl);
41+ #endif
3442 auto object = file.GetObjectChecked (what, cl);
3543 if (!object) {
3644 // it could be that object was stored with previous convention
@@ -73,6 +81,37 @@ void* extractFromTFile(TFile& file, TClass const* cl, const char* what)
7381 return result;
7482}
7583} // namespace
84+
85+ #if defined(_LIBCPP_VERSION)
86+ // The only member of std::array<T,N> is T _M_elems[N] in libstdc++, T __elems_[N] in libc++, so
87+ // objects written on Linux carry a StreamerInfo with a checksum the libc++ class does not have.
88+ // When opening the file, ROOT drops that StreamerInfo as an alias of the in-memory one
89+ // (TStreamerInfo::BuildCheck), and the read fails with "Could not find the StreamerInfo with a
90+ // checksum", leaving the array zero-filled. Register the on-file layout as a version of its own,
91+ // under the in-memory member name, so that the payload, T[N] for both, is read as usual.
92+ void DataRefUtils::registerLibstdcxxStdArray (TFile& file, TClass const * cl)
93+ {
94+ auto * infos = std::strncmp (cl->GetName (), " array<" , 6 ) == 0 ? file.GetStreamerInfoCache () : nullptr ;
95+ auto * onfile = infos ? dynamic_cast <TStreamerInfo*>(infos->FindObject (cl->GetName ())) : nullptr ;
96+ if (!onfile || onfile->GetNelement () != 1 || std::strcmp (onfile->GetElement (0 )->GetName (), " _M_elems" ) != 0 ) {
97+ return ;
98+ }
99+ // Exists before BuildCheck, so that the on-file layout gets a version of its own
100+ auto * current = static_cast <TStreamerInfo*>(const_cast <TClass*>(cl)->GetStreamerInfo ());
101+ auto * info = static_cast <TStreamerInfo*>(cl->FindStreamerInfo (onfile->GetCheckSum ()));
102+ if (!info) {
103+ info = static_cast <TStreamerInfo*>(onfile->Clone ());
104+ info->BuildCheck (&file);
105+ }
106+ // Also when ROOT registered it itself: it then reads nothing, without any error
107+ if (std::strcmp (info->GetElement (0 )->GetName (), current->GetElement (0 )->GetName ()) != 0 ) {
108+ info->GetElement (0 )->SetName (current->GetElement (0 )->GetName ());
109+ info->Clear (" build" );
110+ info->BuildOld ();
111+ }
112+ }
113+ #endif
114+
76115// Adapted from CcdbApi private method interpretAsTMemFileAndExtract
77116// If the former is moved to public, throws on error and could be changed to
78117// not require a mutex we could use it.
0 commit comments