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