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