ATLAS Offline Software
Loading...
Searching...
No Matches
DsoDb.cxx
Go to the documentation of this file.
1
2
3/*
4 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
5*/
6
7// DsoDb.cxx
8// Implementation file for class DsoDb
9// Author: S.Binet<binet@cern.ch>
11
12// AthenaKernel includes
13#include "AthenaKernel/DsoDb.h"
14
15//#define ATH_DSODB_VERBOSE
16
17// STL includes
18#include <cstdlib> /* getenv */
19#include <algorithm>
20#include <iostream>
21#include <print>
22#include <fstream>
23#include <set>
24
25// boost includes
26#include <filesystem>
27#include "boost/tokenizer.hpp"
28
29#include "boost/algorithm/string.hpp"
30
31// ROOT includes
32#include "TClassEdit.h"
33
34// fwk includes
35#include "GaudiKernel/System.h"
36
37namespace fs = std::filesystem;
38
39namespace {
40 typedef std::vector<std::string> Strings_t;
41 const std::string RootMap = ".rootmap";
42 const std::string Components = ".components";
43 const std::string PluginNs= "__pf__";
44
45#ifdef _WIN32
46 const std::string SHLIB_PREFIX = "lib";
47 const std::string SHLIB_SUFFIX = ".dll";
48#else
49 const std::string SHLIB_PREFIX = "lib";
50 const std::string SHLIB_SUFFIX = ".so";
51#endif
52
53
54 bool is_rootcint_dict(const std::string& libname)
55 {
56 if (libname == "liblistDict.so") return true;
57 if (libname == "libmapDict.so") return true;
58 if (libname == "libmap2Dict.so") return true;
59 if (libname == "libmultimapDict.so") return true;
60 if (libname == "libsetDict.so") return true;
61 if (libname == "libvectorDict.so") return true;
62 if (libname == "libCore.so") return true;
63 if (libname == "libMathCore.so") return true;
64
65 static const std::string dll = ".dll";
66 if (libname == dll) {
67 return false;
68 }
69 return !libname.starts_with(SHLIB_PREFIX) && libname.ends_with(dll);
70 }
71
72 inline
73 std::string to_string(const fs::path& p)
74 {
75 return p.string();
76 }
77
78 std::string getlibname(const std::string& libname)
79 {
80 std::string lib = libname;
81 if (!lib.starts_with( "lib")) {
82 lib = std::string("lib") + lib;
83 }
84 if (!lib.ends_with(SHLIB_SUFFIX)) {
85 lib += SHLIB_SUFFIX;
86 }
87 return lib;
88 }
89
90 const std::set<std::string>&
91 s_cxx_builtins()
92 {
93 static const std::set<std::string> s = {
94 "char",
95 "unsigned char",
96 "signed char",
97
98 "signed",
99
100 "short int",
101 "short signed",
102 "short signed int",
103
104 "short",
105 "unsigned short",
106 "signed short",
107
108 "int",
109 "unsigned int",
110
111 "long int",
112 "long signed int",
113 "signed long int",
114
115 "long",
116 "long signed",
117 "signed long",
118 "unsigned long",
119 "unsigned long int",
120
121 "long long",
122 "long long int",
123 "unsigned long long",
124 "longlong",
125
126 "ulonglong",
127
128 "float",
129 "double",
130 "long double",
131 "bool",
132 };
133 return s;
134 }
135
136 const std::map<std::string, std::string>&
137 s_cxx_aliases()
138 {
139 static const std::map<std::string, std::string> s =
140 {{"ElementLinkInt_p1", "ElementLink_p1<unsigned int>"},
141 {"basic_string<char>", "string"},
142 {"vector<basic_string<char> >", "vector<string>"},
143 {"INavigable4MomentumCollection", "DataVector<INavigable4Momentum>"},
144 {"IParticleContainer", "DataVector<IParticle>"},
145 };
146 return s;
147 }
148
149 const std::map<std::string, std::string>&
150 s_cxx_typedefs()
151 {
152 static const std::map<std::string, std::string> s =
153 {{"INavigable4MomentumCollection", "DataVector<INavigable4Momentum>"},
154 {"IParticleContainer", "DataVector<IParticle>"},
155 };
156 return s;
157 }
158
162 std::string
163 to_rootmap_name(const std::string& type_name_)
164 {
165 std::string type_name = type_name_;
166 boost::algorithm::replace_all(type_name, ", ", ",");
167 // first, the easy case: builtins
168 if (s_cxx_builtins().find(type_name) != s_cxx_builtins().end()) {
169 return type_name;
170 }
171
172 // known missing aliases ?
173 if (s_cxx_aliases().find(type_name) != s_cxx_aliases().end()) {
174 return ::to_rootmap_name(s_cxx_aliases().find(type_name)->second);
175 }
176
177 // Protect against data race inside TClassEdit.
178 // https://github.com/root-project/root/issues/10353
179 // Should be fixed in root 6.26.02.
180 {
181 R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
182 type_name = TClassEdit::ShortType(type_name.c_str(),
183 TClassEdit::kDropDefaultAlloc|
184 TClassEdit::kDropStd);
185 }
186 boost::algorithm::replace_all(type_name, "basic_string<char> >", "string>");
187 boost::algorithm::replace_all(type_name, "basic_string<char>", "string");
188 return type_name;
189 }
190
194 std::string
195 to_rflx_name(const std::string& type_name_)
196 {
197 std::string type_name = type_name_;
198 boost::algorithm::replace_all(type_name, ", ", ",");
199 // first the easy case: builtins
200 if (s_cxx_builtins().find(type_name) != s_cxx_builtins().end()) {
201 return type_name;
202 }
203
204 // known missing typedefs ?
205 if (s_cxx_typedefs().find(type_name) != s_cxx_typedefs().end()) {
206 return ::to_rflx_name(s_cxx_typedefs().find(type_name)->second);
207 }
208 {
209 // Protect against data race inside TClassEdit.
210 // https://github.com/root-project/root/issues/10353
211 // Should be fixed in root 6.26.02.
212 R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
213 type_name = TClassEdit::ShortType(type_name.c_str(),
214 TClassEdit::kDropDefaultAlloc);
215 }
216 // !! order matters !! (at least in C++03. C++11 should be good)
217 boost::algorithm::replace_all(type_name,
218 "std::string>",
219 "std::basic_string<char> >");
220 boost::algorithm::replace_all(type_name,
221 "std::string",
222 "std::basic_string<char>");
223 return type_name;
224 }
225}
226
227namespace Ath {
228
230// Public methods:
232
236{
237 static const DsoDb db;
238 return &db;
239}
240
241// Constructors
244 m_pf(),
245 m_db(),
246 m_dsofiles()
247{
249}
250
251// Destructor
255
257// Non-const methods:
259
260bool
261DsoDb::has_type(const std::string& type_name) const
262{
263 if (s_cxx_builtins().find(type_name) != s_cxx_builtins().end()) {
264 return true;
265 }
266 const std::string n = ::to_rootmap_name(type_name);
267 if ( m_db.find(n) != m_db.end() ||
268 m_pf.find(n) != m_pf.end() ) {
269 return true;
270 }
271 return false;
272}
273
274std::string
275DsoDb::load_type ATLAS_NOT_THREAD_SAFE (const std::string& type_name) const
276{
277 RootType t = this->rflx_type(type_name);
278 if (t.Id()) {
279 return t.Name(Reflex::SCOPED|Reflex::QUALIFIED);
280 }
281 return std::string();
282}
283
285// Protected methods:
287
289void
291{
292 typedef boost::tokenizer<boost::char_separator<char> > Tokenizer_t;
293 typedef std::vector<fs::path> Paths_t;
294
295 std::set<std::string> dsofiles;
296
297 std::string dsopath = System::getEnv("LD_LIBRARY_PATH");
298 std::string rootsys = System::getEnv("ROOTSYS");
299
300 Tokenizer_t tok(dsopath, boost::char_separator<char>(":"));
301
302 for (Tokenizer_t::iterator itr = tok.begin(), iend = tok.end();
303 itr != iend;
304 ++itr) {
305 if (itr->starts_with(rootsys)) {
306 continue;
307 }
308 fs::path p(*itr);
309 if (!std::filesystem::exists(*itr)) {
310 continue;
311 }
312 Paths_t dir_content {fs::directory_iterator(p),
313 fs::directory_iterator()};
314 std::sort(dir_content.begin(),
315 dir_content.end());
316 for (Paths_t::iterator ipath = dir_content.begin(),
317 ipath_end = dir_content.end();
318 ipath != ipath_end;
319 ++ipath) {
320 const fs::path& dsomap = *ipath;
321
322 bool is_components = false;
323 if (dsomap.extension() == Components)
324 is_components = true;
325 else if (dsomap.extension() != RootMap)
326 continue;
327
328 if (!fs::exists(dsomap)) continue;
329
330 dsofiles.insert(dsomap.c_str());
331 std::ifstream f(dsomap.c_str());
332 int line_nbr = -1;
333 std::string lastlib;
334 while (f) {
335 line_nbr += 1;
336 std::string line;
337 std::getline(f, line);
338 boost::algorithm::trim(line);
339
340 std::string libname;
341 std::string dso_key;
342 if ( line.empty() )
343 continue;
344
345 else if (line.compare (0, 8, "Library.")==0) {
346 Strings_t ll;
347 boost::algorithm::split(ll, line,
348 boost::is_any_of(" "),
349 boost::token_compress_on);
350 if (ll.size() < 2) {
351 std::print (std::cerr,
352 "DsoDb:: **error** could not parse {}:{}\n"
353 "DsoDb:: (some) reflex-dicts may fail to be autoloaded",
354 dsomap.string(), line_nbr);
355 continue;
356 }
357 libname = ll[1];
358 if (::is_rootcint_dict(libname)) {
359 continue;
360 }
361 dso_key = ll[0];
362 libname = ::getlibname(libname);
363 boost::algorithm::replace_all(dso_key, "Library.", "");
364 boost::algorithm::replace_all(dso_key, ":", "");
365 std::replace(dso_key.begin(), dso_key.end(), '@', ':');
366 std::replace(dso_key.begin(), dso_key.end(), '-', ' ');
367 }
368
369 else if (line[0] == '[') {
370 libname = line.substr (1, line.size()-2);
371 boost::algorithm::trim (libname);
372 if (::is_rootcint_dict(libname)) {
373 lastlib.clear();
374 continue;
375 }
376 if (!libname.empty())
377 lastlib = ::getlibname (libname);
378 continue;
379 }
380
381 else if (line.compare(0, 8, "# --End ")==0) {
382 lastlib.clear();
383 continue;
384 }
385
386 else if (line.compare(0, 6, "class ")==0) {
387 libname = lastlib;
388 line.erase (0, 6);
389 dso_key = std::move(line);
390 }
391
392 else if (is_components && line.compare(0, 3, "lib") ==0) {
393 std::string::size_type pos = line.find (':');
394 if (pos == std::string::npos) continue;
395 libname = line.substr(0, pos);
396 line.erase (0, pos+1);
397 dso_key = std::move(line);
398
399 if (dso_key.compare(0, 6, "_PERS_")==0 ||
400 dso_key.compare(0, 7, "_TRANS_")==0)
401 continue;
402
403 if (libname.find ("AthenaPoolPoolCnv") != std::string::npos)
404 continue;
405 }
406
407 if (libname.empty() || dso_key.empty()) continue;
408
409 const std::string fullpath_libname = to_string(dsomap.parent_path() / fs::path(libname));
410
411 DsoMap_t *db = NULL;
412 if (dso_key.starts_with(PluginNs) || is_components) {
413 db = &m_pf;
414 } else {
415 db = &m_db;
416 }
417 if (db->find(dso_key) == db->end()) {
418 db->insert(std::make_pair(dso_key, Strings_t()));
419 }
420 (*db)[dso_key].push_back(std::move(fullpath_libname));
421 }
422 }
423 }
424
425 m_dsofiles.reserve(dsofiles.size());
426 std::copy(dsofiles.begin(), dsofiles.end(), std::back_inserter(m_dsofiles));
427
428 return;
429}
430
431std::vector<std::string>
432DsoDb::capabilities(const std::string& libname_) const
433{
434 fs::path p(libname_);
435
436 const std::string libname = ::getlibname(to_string(p.filename()));
437 std::set<std::string> caps;
438 const DsoMap_t* dbs[] = { &m_pf, &m_db };
439
440 for (std::size_t i = 0, imax = 2; i < imax; ++i) {
441 const DsoMap_t* db = dbs[i];
442 for (DsoMap_t::const_iterator idb = db->begin(), iend=db->end();
443 idb != iend;
444 ++idb) {
445 for (Libs_t::const_iterator ilib = idb->second.begin(),
446 ilibend = idb->second.end();
447 ilib != ilibend;
448 ++ilib) {
449 fs::path lib(*ilib);
450 if (to_string(lib.filename()) == libname) {
451 caps.insert(idb->first);
452 }
453 }
454 }
455 }
456
457 return std::vector<std::string>(caps.begin(), caps.end());
458}
459
462DsoDb::duplicates(const std::string& libname, bool pedantic) const
463{
464 DsoMap_t dups;
465 const std::string basename_lib = to_string(fs::path(libname).filename());
466 std::vector<std::string> caps = this->capabilities(libname);
467 const DsoMap_t* dbs[] = { &m_pf, &m_db };
468
469 for (std::size_t i = 0, imax = 2; i < imax; ++i) {
470 DsoMap_t dup_db;
471 this->get_dups(dup_db, *dbs[i], pedantic);
472 for (DsoMap_t::const_iterator
473 idb = dup_db.begin(),
474 idbend = dup_db.end();
475 idb != idbend;
476 ++idb) {
477 if (std::find(caps.begin(), caps.end(), idb->first) != caps.end()) {
478 for (Libs_t::const_iterator
479 ilib = idb->second.begin(),
480 ilibend=idb->second.end();
481 ilib != ilibend;
482 ++ilib) {
483 fs::path p(*ilib);
484 const std::string basename = to_string(p.filename());
485 if (basename != libname) {
486 dups[idb->first].push_back(*ilib);
487 }
488 }
489 }
490 }
491 }
492 return dups;
493}
494
497DsoDb::dict_duplicates(bool pedantic) const
498{
499 DsoMap_t dups;
500 get_dups(dups, m_db, pedantic);
501 return dups;
502}
503
506DsoDb::pf_duplicates(bool pedantic) const
507{
508 DsoMap_t dups;
509 get_dups(dups, m_pf, pedantic);
510 return dups;
511}
512
516DsoDb::libs(bool detailed) const
517{
518 std::set<std::string> libs;
519 const DsoMap_t* dbs[] = { &m_pf, &m_db };
520
521 for (std::size_t i = 0, imax = 2; i < imax; ++i) {
522 const DsoMap_t& db = *dbs[i];
523 for (DsoMap_t::const_iterator idb = db.begin(), iend=db.end();
524 idb != iend;
525 ++idb) {
526 for (Libs_t::const_iterator
527 ilib = idb->second.begin(),
528 ilibend=idb->second.end();
529 ilib != ilibend;
530 ++ilib) {
531 if (detailed) {
532 libs.insert(*ilib);
533 } else {
534 libs.insert(to_string(fs::path(*ilib).filename()));
535 }
536 }
537 }
538 }
539 return Libs_t(libs.begin(), libs.end());
540}
541
546DsoDb::content(bool pedantic) const
547{
548 DsoMap_t db;
549
550 const DsoMap_t* dbs[] = { &m_pf, &m_db };
551 for (std::size_t i = 0, imax = 2; i < imax; ++i) {
552 const DsoMap_t& d = *dbs[i];
553 for (DsoMap_t::const_iterator idb = d.begin(), idbend=d.end();
554 idb != idbend;
555 ++idb) {
556 if (pedantic) {
557 db[idb->first] = idb->second;
558 } else {
559 Libs_t libs;
560 std::set<std::string> baselibs;
561 for (Libs_t::const_iterator
562 ilib = idb->second.begin(),
563 ilibend= idb->second.end();
564 ilib != ilibend;
565 ++ilib) {
566 const std::string baselib = to_string(fs::path(*ilib).filename());
567 if (baselibs.find(baselib) == baselibs.end()) {
568 libs.push_back(*ilib);
569 baselibs.insert(std::move(baselib));
570 }
571 }
572 db[idb->first] = std::move(libs);
573 }
574 }
575 }
576
577 return db;
578}
579
581void
582DsoDb::get_dups(DsoMap_t& dups, const DsoMap_t& db, bool pedantic) const
583{
584 for (DsoMap_t::const_iterator idb = db.begin(), iend = db.end();
585 idb != iend;
586 ++idb) {
587 if (idb->second.size() == 1) {
588 continue;
589 }
590 Libs_t libs;
591 if (pedantic) {
592 libs = idb->second;
593 } else {
594 std::unordered_set<std::string> baselibs;
595 for (Libs_t::const_iterator
596 ilib = idb->second.begin(),
597 ilend= idb->second.end();
598 ilib != ilend;
599 ++ilib)
600 {
601 fs::path p(*ilib);
602 if (! baselibs.emplace (to_string(p.filename())) . second) {
603 // String wasn't in the set.
604 libs.push_back(*ilib);
605 }
606 }
607 }
608 if (libs.size() > 1) {
609 dups[idb->first] = std::move(libs);
610 }
611 }
612}
613
616DsoDb::rflx_type ATLAS_NOT_THREAD_SAFE (const std::string& type_name) const
617{
618 const std::string rootmap_name = ::to_rootmap_name(type_name);
619 const std::string rflx_name = ::to_rflx_name(type_name);
620
621 if (s_cxx_builtins().find(type_name) != s_cxx_builtins().end()) {
622 return RootType(rflx_name);
623 }
624
625 if (!this->has_type(rootmap_name)) {
626#ifdef ATH_DSODB_VERBOSE
627 std::println (std::cerr,
628 "DsoDb **error**: no such type [{}] in rootmap files",
629 rootmap_name);
630#endif
631 return RootType();
632 }
633 DsoMap_t::const_iterator idb = m_db.find(rootmap_name);
634 if (idb == m_db.end()) {
635 // try plugin factories...
636 idb = m_pf.find(rootmap_name);
637 if (idb == m_pf.end()) {
638 return RootType();
639 }
640 }
641 const Libs_t& libs = idb->second;
642 if (libs.empty()) {
643#ifdef ATH_DSODB_VERBOSE
644 std::println (std::cerr, "DsoDb **error**: no library hosting [{}]",
645 type_name);
646#endif
647 return RootType();
648 }
649
650 System::ImageHandle handle;
651 std::string libname = ::to_string(fs::path(libs[0]).filename());
652 boost::algorithm::trim(libname);
653 if (libname.starts_with(SHLIB_PREFIX)) {
654 libname = libname.substr(SHLIB_PREFIX.size(), std::string::npos);
655 }
656 if (libname.ends_with(SHLIB_SUFFIX)) {
657 libname.resize(libname.size() - SHLIB_SUFFIX.size());
658 }
659
660 unsigned long err = System::loadDynamicLib( libname, &handle );
661 if ( err != 1 ) {
662 std::println (std::cerr,
663 "DsoDb **error**: could not load library [{}] ({})",
664 libs[0], System::getLastErrorString());
665 return RootType();
666 }
667
668 return RootType(rflx_name);
669}
670
671} //> end namespace Ath
static std::string to_string(const std::vector< T > &v)
static Double_t fs
TTypeAdapter RootType
Definition RootType.h:211
int imax(int i, int j)
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
DsoMap_t pf_duplicates(bool pedantic=false) const
table of plugin-factories-duplicates: {type: [lib1, lib2, ...]}
Definition DsoDb.cxx:506
DsoMap_t m_db
repository of components
Definition DsoDb.h:153
std::vector< std::string > Libs_t
Definition DsoDb.h:36
Libs_t libs(bool detailed=false) const
list of all libraries we know about
Definition DsoDb.cxx:516
std::vector< std::string > m_dsofiles
list of dsofiles
Definition DsoDb.h:156
~DsoDb()
Destructor:
Definition DsoDb.cxx:253
std::unordered_map< std::string, Libs_t > DsoMap_t
Definition DsoDb.h:37
void build_repository()
initialize the repository of dso file names
Definition DsoDb.cxx:290
DsoDb()
Default constructor:
Definition DsoDb.cxx:243
std::vector< std::string > capabilities(const std::string &libname) const
list of reflex-types associated with a library name
Definition DsoDb.cxx:432
bool has_type(const std::string &type_name) const
Definition DsoDb.cxx:261
void get_dups(DsoMap_t &dups, const DsoMap_t &db, bool pedantic) const
get the duplicates for a given repository of components
Definition DsoDb.cxx:582
const DsoMap_t & db() const
repository of components
Definition DsoDb.h:94
static const DsoDb * instance()
factory for the DsoDb
Definition DsoDb.cxx:235
DsoMap_t dict_duplicates(bool pedantic=false) const
table of dict-duplicates: {type: [lib1, lib2, ...]}
Definition DsoDb.cxx:497
DsoMap_t m_pf
repository of plugin factories
Definition DsoDb.h:150
DsoMap_t content(bool pedantic) const
return the table {type: [lib1, ...]} - concatenation of all dict-entries and plugin-factories entries...
Definition DsoDb.cxx:546
DsoMap_t duplicates(const std::string &libname, bool pedantic=false) const
list of libraries hosting duplicate reflex-types
Definition DsoDb.cxx:462
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:140
virtual void handle(const Incident &inc)
Handle end of run incidents to save the metadata at that point.
@ SCOPED
Definition RootType.h:27
@ QUALIFIED
Definition RootType.h:26
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
std::string basename(std::string name)
Definition utils.cxx:207