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