91 std::string
demangle(
const std::string&
id ) {
93 auto realname = std::unique_ptr<char, decltype( free )*>(
94 abi::__cxa_demangle(
id.c_str(),
nullptr,
nullptr, &status ), free );
95 if ( !realname )
return id;
96 std::string result = realname.get();
98 result = std::regex_replace(
100 std::regex{
"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >( (?=>))?" },
103 result = std::regex_replace( result, std::regex{
"std::__1::" },
"std::" );
105 result = std::regex_replace(
106 result, std::regex{
"std::basic_string<char, std::char_traits<char>, std::allocator<char>>( (?=>))?" },
109 result = std::regex_replace( result, std::regex{
">>" },
"> >" );
110 result = std::regex_replace( result, std::regex{
">>" },
"> >" );
115 Registry& Registry::instance() {
116 auto _guard = std::scoped_lock{ ::registrySingletonMutex };
122 if (
logger().level() <= Logger::Debug ) {
123 std::stringstream msg;
124 const auto& info = Registry::instance().getInfo(
id );
125 msg <<
"bad any_cast: requested factory " <<
id <<
" of type " <<
demangle( factory_type ) <<
", got ";
127 msg <<
demangle( info.factory.type() ) <<
" from " << info.library;
130 logger().debug( msg.str() );
134 Registry::Properties::mapped_type Registry::FactoryInfo::getprop(
const Properties::key_type& name )
const {
135 auto p = properties.find( name );
136 return ( p != end( properties ) ) ? p->second : Properties::mapped_type{};
139 Registry::Registry() {}
141 void Registry::initialize() {
142 auto _guard = std::scoped_lock{ m_mutex };
144 std::regex line_format{
"^(?:[[:space:]]*(?:(v[0-9]+)::)?([^:]+):(.*[^[:space:]]))?[[:space:]]*(?:#.*)?$" };
148 logger().debug(
" looking into " + dir );
150 if ( !fs::is_directory( dir ) ) {
continue; }
151 for (
const auto& p : fs::directory_iterator( dir ) ) {
152 if ( p.path().extension() !=
".components" || !is_regular_file( p.path() ) ) {
continue; }
154 const auto& fullPath = p.path().string();
155 logger().debug(
" reading " + p.path().filename().string() );
158 int factoriesCount = 0;
162 std::getline( factories, line );
163 if ( regex_match( line, m, line_format ) ) {
164 if ( m[1] !=
"v2" ) {
continue; }
165 const std::string lib{
m[2] };
166 const std::string fact{
m[3] };
167 m_factories.emplace( fact, FactoryInfo{ lib, {}, { {
"ClassName", fact } } } );
168#ifdef GAUDI_REFLEX_COMPONENT_ALIASES
170 std::string old_name = old_style_name( fact );
171 if ( fact != old_name ) {
172 m_factories.emplace( old_name,
173 FactoryInfo{ lib, {}, { {
"ReflexName",
"true" }, {
"ClassName", fact } } } );
178 logger().warning(
"failed to parse line " + fullPath +
':' + std::to_string( lineCount ) );
182 logger().debug(
" found " + std::to_string( factoriesCount ) +
" factories" );
188 const Registry::FactoryMap& Registry::factories()
const {
189 std::call_once( m_initialized, &Registry::initialize,
const_cast<Registry*
>(
this ) );
193 Registry::FactoryMap& Registry::factories() {
194 std::call_once( m_initialized, &Registry::initialize,
this );
198 Registry::FactoryInfo& Registry::add(
const KeyType&
id, FactoryInfo info ) {
199 auto _guard = std::scoped_lock{ m_mutex };
202#ifdef GAUDI_REFLEX_COMPONENT_ALIASES
204 const auto old_name = old_style_name(
id );
205 if (
id != old_name ) {
206 auto new_info = info;
208 new_info.properties[
"ReflexName"] =
"true";
210 add( old_name, new_info );
214 auto entry = facts.find(
id );
215 if ( entry == facts.end() ) {
217 entry = facts.emplace(
id, std::move( info ) ).first;
220 if ( !entry->second.is_set() ) entry->second = std::move( info );
222 return entry->second;
225 Registry::FactoryMap::size_type Registry::erase(
const KeyType&
id ) {
226 auto _guard = std::scoped_lock{ m_mutex };
228 return facts.erase(
id );
231 const Registry::FactoryInfo& Registry::getInfo(
const KeyType&
id,
const bool load )
const {
232 auto _guard = std::scoped_lock{ m_mutex };
233 static const FactoryInfo unknown = {
"unknown" };
235 auto f = facts.find(
id );
237 if ( f == facts.end() ) {
return unknown; }
238 if ( !load || f->second.is_set() ) {
return f->second; }
240 if ( !loadPluginLibrary( f->second.library ) ) {
return unknown; }
242 f = facts.find(
id );
246 Registry& Registry::addProperty(
const KeyType&
id,
const KeyType& k,
const std::string& v ) {
247 auto _guard = std::scoped_lock{ m_mutex };
249 auto f = facts.find(
id );
251 if ( f != facts.end() ) f->second.properties[k] =
v;
255 void Registry::setError(
const KeyType& warning ) { m_werror.insert( warning ); }
257 void Registry::unsetError(
const KeyType& warning ) { m_werror.erase( warning ); }
259 std::set<Registry::KeyType> Registry::loadedFactoryNames()
const {
260 auto _guard = std::scoped_lock{ m_mutex };
263 if ( f.second.is_set() )
l.insert( f.first );
268 bool Registry::loadPluginLibrary( std::string_view library )
const {
270 if ( !fs::exists( dir ) ) {
continue; }
271 const auto path = dir / fs::path( library );
272 if ( is_regular_file( path ) ) {
273 if ( dlopen(
path.c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
276 logger().warning(
"cannot load " +
path.string() );
277 if (
char* dlmsg = dlerror() ) {
logger().warning( dlmsg ); }
282 if ( dlopen( std::string{ library }.c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
return true; }
284 logger().warning(
"cannot load " + std::string{ library } );
285 if (
char* dlmsg = dlerror() ) {
logger().warning( dlmsg ); }
289 void Logger::report( Level lvl,
const std::string& msg ) {
290 static const char* levels[] = {
"DEBUG : ",
"INFO : ",
"WARNING: ",
"ERROR : " };
291 if ( lvl >=
level() ) { std::cerr << levels[lvl] <<
msg << std::endl; }
294 static auto s_logger = std::make_unique<Logger>();
300#if defined _GNU_SOURCE || defined __APPLE__
302 if ( dladdr( fptr, &info ) == 0 )
return "";
304 auto pos = std::strrchr( info.dli_fname,
'/' );
308 return info.dli_fname;
316#ifdef PLUGIN_PATH_RELATIVE
317# define stringify( x ) stringify_( x )
318# define stringify_( x ) #x
319 std::string relative_path = stringify( PLUGIN_PATH_RELATIVE );
321 std::string relative_path =
".";
324 if ( dladdr( (
void*)_dso_marker, &info ) != 0 ) {
325 auto plugin_path = fs::path( info.dli_fname ).parent_path() / relative_path;
326 return plugin_path.string();
328 return relative_path;
338 constexpr char const* envVars[] =
339#if defined( __APPLE__ )
340 {
"GAUDI_PLUGIN_PATH",
"DYLD_LIBRARY_PATH" };
342 {
"GAUDI_PLUGIN_PATH",
"LD_LIBRARY_PATH" };
346 static std::vector<std::string> search_path;
347 static std::once_flag initialized;
348 std::call_once( initialized, [&]() {
349 for (
const auto& envVar : envVars ) {
350 if (
auto ptr = std::getenv( envVar ) ) {
351 std::string_view path{ ptr };
352 while ( !path.empty() ) {
353 auto sep = path.find(
':' );
354 std::string dirname = std::string{ path.substr( 0, sep ) };
356 if ( find( search_path.begin(), search_path.end(), dirname ) == search_path.end() ) {
357 search_path.emplace_back( std::move( dirname ) );
360 if ( sep != std::string_view::npos ) {
361 path = path.substr( sep + 1 );