File indexing completed on 2026-09-21 08:24:49
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #define GAUDI_PLUGIN_SERVICE_V2
0015 #include <Gaudi/PluginService.h>
0016
0017 #include <boost/algorithm/string.hpp>
0018
0019 #include <dirent.h>
0020 #include <dlfcn.h>
0021
0022 #include <cstdlib>
0023 #include <fstream>
0024 #include <iostream>
0025 #include <memory>
0026 #include <regex>
0027 #include <vector>
0028
0029 #include <cxxabi.h>
0030 #include <sys/stat.h>
0031
0032 #ifdef _GNU_SOURCE
0033 # include <cstring>
0034 # include <dlfcn.h>
0035 #endif
0036
0037 #ifdef USE_BOOST_FILESYSTEM
0038 # include <boost/filesystem.hpp>
0039 namespace fs = boost::filesystem;
0040 #else
0041 # include <filesystem>
0042 namespace fs = std::filesystem;
0043 #endif
0044
0045 #include <string_view>
0046
0047 #define REG_SCOPE_LOCK std::lock_guard<std::recursive_mutex> _guard( m_mutex );
0048
0049 namespace {
0050 std::mutex registrySingletonMutex;
0051 }
0052 #define SINGLETON_LOCK std::lock_guard<std::mutex> _guard( ::registrySingletonMutex );
0053
0054 #include <algorithm>
0055
0056 namespace {
0057 struct OldStyleCnv {
0058 std::string name;
0059 void operator()( const char c ) {
0060 switch ( c ) {
0061 case '<':
0062 case '>':
0063 case ',':
0064 case '(':
0065 case ')':
0066 case ':':
0067 case '.':
0068 name.push_back( '_' );
0069 break;
0070 case '&':
0071 name.push_back( 'r' );
0072 break;
0073 case '*':
0074 name.push_back( 'p' );
0075 break;
0076 case ' ':
0077 break;
0078 default:
0079 name.push_back( c );
0080 break;
0081 }
0082 }
0083 };
0084
0085 std::string old_style_name( const std::string& name ) {
0086 return std::for_each( name.begin(), name.end(), OldStyleCnv() ).name;
0087 }
0088 }
0089
0090 namespace Gaudi {
0091 namespace PluginService {
0092 GAUDI_PLUGIN_SERVICE_V2_INLINE namespace v2 {
0093 namespace Details {
0094 std::string demangle( const std::string& id ) {
0095 int status;
0096 auto realname = std::unique_ptr<char, decltype( free )*>(
0097 abi::__cxa_demangle( id.c_str(), nullptr, nullptr, &status ), free );
0098 if ( !realname ) return id;
0099 #if _GLIBCXX_USE_CXX11_ABI
0100 return std::regex_replace(
0101 realname.get(),
0102 std::regex{"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >( (?=>))?"},
0103 "std::string" );
0104 #else
0105 return std::string{realname.get()};
0106 #endif
0107 }
0108 std::string demangle( const std::type_info& id ) { return demangle( id.name() ); }
0109
0110 Registry& Registry::instance() {
0111 SINGLETON_LOCK
0112 static Registry r;
0113 return r;
0114 }
0115
0116 void reportBadAnyCast( const std::type_info& factory_type, const std::string& id ) {
0117 if ( logger().level() <= Logger::Debug ) {
0118 std::stringstream msg;
0119 const auto& info = Registry::instance().getInfo( id );
0120 msg << "bad any_cast: requested factory " << id << " of type " << demangle( factory_type ) << ", got ";
0121 if ( info.is_set() )
0122 msg << demangle( info.factory.type() ) << " from " << info.library;
0123 else
0124 msg << "nothing";
0125 logger().debug( msg.str() );
0126 }
0127 }
0128
0129 Registry::Properties::mapped_type Registry::FactoryInfo::getprop( const Properties::key_type& name ) const {
0130 auto p = properties.find( name );
0131 return ( p != end( properties ) ) ? p->second : Properties::mapped_type{};
0132 }
0133
0134 Registry::Registry() {}
0135
0136 void Registry::initialize() {
0137 REG_SCOPE_LOCK
0138 #if defined( _WIN32 )
0139 const std::string envVar = "PATH";
0140 const std::string sep = ";";
0141 #elif defined( __APPLE__ )
0142 const std::string envVar = "DYLD_LIBRARY_PATH";
0143 const std::string sep = ":";
0144 #else
0145 const std::string envVar = "LD_LIBRARY_PATH";
0146 const std::string sep = ":";
0147 #endif
0148
0149 std::regex line_format{"^(?:[[:space:]]*(?:(v[0-9]+)::)?([^:]+):(.*[^[:space:]]))?[[:space:]]*(?:#.*)?$"};
0150 std::smatch matches;
0151
0152 std::string search_path;
0153 const char* envPtr = std::getenv( envVar.c_str() );
0154 search_path = envPtr ? envPtr : "/usr/lib64:/usr/lib:/usr/local/lib";
0155 if ( search_path.empty() ) {
0156 return;
0157 }
0158
0159 logger().debug("searching factories in " + envVar);
0160 logger().debug("searching factories in " + search_path);
0161
0162 std::vector<std::string> directories;
0163 boost::split(directories, search_path, boost::is_any_of(sep));
0164
0165 for(fs::path dirName: directories) {
0166 if ( not is_directory( dirName ) ) {
0167 continue;
0168 }
0169 logger().debug( " looking into " + dirName.string() );
0170 for ( auto& p : fs::directory_iterator( dirName ) ) {
0171
0172 if ( p.path().extension() == ".components" && is_regular_file( p.path() ) ) {
0173
0174 const auto& fullPath = p.path().string();
0175 logger().debug( " reading " + p.path().filename().string() );
0176 std::ifstream factories{fullPath};
0177 std::string line;
0178 int factoriesCount = 0;
0179 int lineCount = 0;
0180 while ( !factories.eof() ) {
0181 ++lineCount;
0182 std::getline( factories, line );
0183 if ( regex_match( line, matches, line_format ) ) {
0184 if ( matches[1] == "v2" ) {
0185 const std::string lib{matches[2]};
0186 const std::string fact{matches[3]};
0187 m_factories.emplace( fact, FactoryInfo{lib, {}, {{"ClassName", fact}}} );
0188 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
0189
0190 std::string old_name = old_style_name( fact );
0191 if ( fact != old_name ) {
0192 m_factories.emplace( old_name,
0193 FactoryInfo{lib, {}, {{"ReflexName", "true"}, {"ClassName", fact}}} );
0194 }
0195 #endif
0196 ++factoriesCount;
0197 }
0198 } else {
0199 logger().debug( "failed to parse line " + fullPath + ':' + std::to_string( lineCount ) );
0200 }
0201 }
0202 if ( logger().level() <= Logger::Debug ) {
0203 logger().debug( " found " + std::to_string( factoriesCount ) + " factories" );
0204 }
0205 }
0206 }
0207 }
0208 }
0209
0210 const Registry::FactoryMap& Registry::factories() const {
0211 std::call_once( m_initialized, &Registry::initialize, const_cast<Registry*>( this ) );
0212 return m_factories;
0213 }
0214
0215 Registry::FactoryMap& Registry::factories() {
0216 std::call_once( m_initialized, &Registry::initialize, this );
0217 return m_factories;
0218 }
0219
0220 Registry::FactoryInfo& Registry::add( const KeyType& id, FactoryInfo info ) {
0221 REG_SCOPE_LOCK
0222 FactoryMap& facts = factories();
0223
0224 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
0225
0226 const auto old_name = old_style_name( id );
0227 if ( id != old_name ) {
0228 auto new_info = info;
0229
0230 new_info.properties["ReflexName"] = "true";
0231
0232 add( old_name, new_info );
0233 }
0234 #endif
0235
0236 auto entry = facts.find( id );
0237 if ( entry == facts.end() ) {
0238
0239 entry = facts.emplace( id, std::move( info ) ).first;
0240 } else {
0241
0242 if ( !entry->second.is_set() ) entry->second = std::move( info );
0243 }
0244 return entry->second;
0245 }
0246
0247 const Registry::FactoryInfo& Registry::getInfo( const KeyType& id, const bool load ) const {
0248 REG_SCOPE_LOCK
0249 static const FactoryInfo unknown = {"unknown"};
0250 const FactoryMap& facts = factories();
0251 auto f = facts.find( id );
0252
0253 if ( f != facts.end() ) {
0254 if ( load && !f->second.is_set() ) {
0255 const std::string library = f->second.library;
0256 if ( !dlopen( library.c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
0257 logger().warning( "cannot load " + library + " for factory " + id );
0258 char* dlmsg = dlerror();
0259 if ( dlmsg ) logger().warning( dlmsg );
0260 return unknown;
0261 }
0262 f = facts.find( id );
0263 }
0264 return f->second;
0265 } else {
0266 return unknown;
0267 }
0268 }
0269
0270 Registry& Registry::addProperty( const KeyType& id, const KeyType& k, const std::string& v ) {
0271 REG_SCOPE_LOCK
0272 FactoryMap& facts = factories();
0273 auto f = facts.find( id );
0274
0275 if ( f != facts.end() ) f->second.properties[k] = v;
0276 return *this;
0277 }
0278
0279 std::set<Registry::KeyType> Registry::loadedFactoryNames() const {
0280 REG_SCOPE_LOCK
0281 std::set<KeyType> l;
0282 for ( const auto& f : factories() ) {
0283 if ( f.second.is_set() ) l.insert( f.first );
0284 }
0285 return l;
0286 }
0287
0288 void Logger::report( Level lvl, const std::string& msg ) {
0289 static const char* levels[] = {"DEBUG : ", "INFO : ", "WARNING: ", "ERROR : "};
0290 if ( lvl >= level() ) { std::cerr << levels[lvl] << msg << std::endl; }
0291 }
0292
0293 static auto s_logger = std::make_unique<Logger>();
0294 Logger& logger() { return *s_logger; }
0295 void setLogger( Logger* logger ) { s_logger.reset( logger ); }
0296
0297
0298 std::string getDSONameFor( void* fptr ) {
0299 #ifdef _GNU_SOURCE
0300 Dl_info info;
0301 if ( dladdr( fptr, &info ) == 0 ) return "";
0302
0303 auto pos = std::strrchr( info.dli_fname, '/' );
0304 if ( pos )
0305 ++pos;
0306 else
0307 return info.dli_fname;
0308 return pos;
0309 #else
0310 return "";
0311 #endif
0312 }
0313 }
0314
0315 void SetDebug( int debugLevel ) {
0316 using namespace Details;
0317 Logger& l = logger();
0318 if ( debugLevel > 1 )
0319 l.setLevel( Logger::Debug );
0320 else if ( debugLevel > 0 )
0321 l.setLevel( Logger::Info );
0322 else
0323 l.setLevel( Logger::Warning );
0324 }
0325
0326 int Debug() {
0327 using namespace Details;
0328 switch ( logger().level() ) {
0329 case Logger::Debug:
0330 return 2;
0331 case Logger::Info:
0332 return 1;
0333 default:
0334 return 0;
0335 }
0336 }
0337 }
0338 }
0339 }