Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-21 08:24:49

0001 /*****************************************************************************\
0002 * (c) Copyright 2013 CERN                                                     *
0003 *                                                                             *
0004 * This software is distributed under the terms of the GNU General Public      *
0005 * Licence version 3 (GPL Version 3), copied verbatim in the file "LICENCE".   *
0006 *                                                                             *
0007 * In applying this licence, CERN does not waive the privileges and immunities *
0008 * granted to it by virtue of its status as an Intergovernmental Organization  *
0009 * or submit itself to any jurisdiction.                                       *
0010 \*****************************************************************************/
0011 
0012 /// @author Marco Clemencic <marco.clemencic@cern.ch>
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 // USE_BOOST_FILESYSTEM
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   /// Convert a class name in the string used with the Reflex plugin service
0085   std::string old_style_name( const std::string& name ) {
0086     return std::for_each( name.begin(), name.end(), OldStyleCnv() ).name;
0087   }
0088 } // namespace
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               // look for files called "*.components" in the directory
0172               if ( p.path().extension() == ".components" && is_regular_file( p.path() ) ) {
0173                 // read the file
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" ) { // ignore non "v2" and "empty" lines
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                       // add an alias for the factory using the Reflex convention
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           // add an alias for the factory using the Reflex convention
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             // this factory was not known yet
0239             entry = facts.emplace( id, std::move( info ) ).first;
0240           } else {
0241             // do not replace an existing factory with a new one
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 ); // ensure that the iterator is valid
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         // This chunk of code was taken from GaudiKernel (genconf) DsoUtils.h
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       } // namespace Details
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   } // namespace PluginService
0339 } // namespace Gaudi