14 #define GAUDI_PLUGIN_SERVICE_V2
25 #include <string_view>
35 #ifdef USE_BOOST_FILESYSTEM
36 # include <boost/filesystem.hpp>
37 namespace fs = boost::filesystem;
39 # include <filesystem>
40 namespace fs = std::filesystem;
41 #endif // USE_BOOST_FILESYSTEM
44 std::mutex registrySingletonMutex;
52 void operator()(
const char c ) {
61 name.push_back(
'_' );
64 name.push_back(
'r' );
67 name.push_back(
'p' );
78 std::string old_style_name(
const std::string&
name ) {
84 namespace PluginService {
87 std::string
demangle(
const std::string&
id ) {
89 auto realname = std::unique_ptr<char, decltype( free )*>(
90 abi::__cxa_demangle(
id.c_str(),
nullptr,
nullptr, &status ), free );
91 if ( !realname )
return id;
92 return std::regex_replace(
94 std::regex{
"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >( (?=>))?" },
99 bool Registry::tryDLOpen(
const std::string_view& libName )
const {
100 const void* handle = dlopen( libName.data(), RTLD_LAZY | RTLD_GLOBAL );
102 std::cout <<
"dlopen failed for " << libName << std::endl;
103 logger().warning(
"cannot load " + std::string( libName ) );
104 if (
char* dlmsg = dlerror() ) {
logger().warning( dlmsg ); }
110 Registry& Registry::instance() {
111 auto _guard = std::scoped_lock{ ::registrySingletonMutex };
118 std::stringstream
msg;
119 const auto& info = Registry::instance().getInfo(
id );
120 msg <<
"bad any_cast: requested factory " <<
id <<
" of type " <<
demangle( factory_type ) <<
", got ";
122 msg <<
demangle( info.factory.type() ) <<
" from " << info.library;
129 Registry::Properties::mapped_type Registry::FactoryInfo::getprop(
const Properties::key_type&
name )
const {
131 return ( p !=
end(
properties ) ) ? p->second : Properties::mapped_type{};
134 Registry::Registry() {}
136 void Registry::initialize() {
137 auto _guard = std::scoped_lock{ m_mutex };
138 #if defined( _WIN32 )
139 const auto envVars = {
"PATH" };
140 const char sep =
';';
141 #elif defined( __APPLE__ )
142 const auto envVars = {
"GAUDI_PLUGIN_PATH" };
143 const char sep =
':';
145 const auto envVars = {
"GAUDI_PLUGIN_PATH",
"LD_LIBRARY_PATH" };
146 const char sep =
':';
149 std::regex line_format{
"^(?:[[:space:]]*(?:(v[0-9]+)::)?([^:]+):(.*[^[:space:]]))?[[:space:]]*(?:#.*)?$" };
150 for (
const auto& envVar : envVars ) {
152 std::stringstream search_path;
153 if (
auto ptr = std::getenv( envVar ) ) search_path << ptr;
154 logger().debug( std::string(
"searching factories in " ) + envVar );
158 while ( std::getline( search_path, dir, sep ) ) {
160 logger().debug(
" looking into " + dir );
162 if ( !fs::is_directory( dir ) ) {
continue; }
163 for (
const auto& p : fs::directory_iterator( dir ) ) {
164 if ( p.path().extension() !=
".components" || !is_regular_file( p.path() ) ) {
continue; }
166 const auto& fullPath = p.path().string();
167 logger().debug(
" reading " + p.path().filename().string() );
170 int factoriesCount = 0;
175 if ( regex_match(
line,
m, line_format ) ) {
176 if (
m[1] !=
"v2" ) {
continue; }
177 const std::string lib{
m[2] };
178 const std::string fact{
m[3] };
179 m_factories.emplace( fact, FactoryInfo{ lib, {}, { {
"ClassName", fact } } } );
180 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
182 std::string old_name = old_style_name( fact );
183 if ( fact != old_name ) {
185 old_name, FactoryInfo{ lib, {}, { {
"ReflexName",
"true" }, {
"ClassName", fact } } } );
190 logger().warning(
"failed to parse line " + fullPath +
':' + std::to_string( lineCount ) );
194 logger().debug(
" found " + std::to_string( factoriesCount ) +
" factories" );
202 std::call_once( m_initialized, &Registry::initialize,
const_cast<Registry*
>(
this ) );
207 std::call_once( m_initialized, &Registry::initialize,
this );
211 Registry::FactoryInfo&
Registry::add(
const KeyType&
id, FactoryInfo info ) {
212 auto _guard = std::scoped_lock{ m_mutex };
215 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
217 const auto old_name = old_style_name(
id );
218 if (
id != old_name ) {
219 auto new_info = info;
221 new_info.properties[
"ReflexName"] =
"true";
223 add( old_name, new_info );
227 auto entry = facts.find(
id );
228 if ( entry == facts.end() ) {
230 entry = facts.emplace(
id, std::move( info ) ).first;
233 if ( !entry->second.is_set() ) entry->second = std::move( info );
235 return entry->second;
238 Registry::FactoryMap::size_type Registry::erase(
const KeyType&
id ) {
239 auto _guard = std::scoped_lock{ m_mutex };
241 return facts.erase(
id );
244 const Registry::FactoryInfo& Registry::getInfo(
const KeyType&
id,
const bool load )
const {
245 auto _guard = std::scoped_lock{ m_mutex };
246 static const FactoryInfo unknown = {
"unknown" };
248 auto f = facts.find(
id );
250 if ( f == facts.end() ) {
return unknown; }
251 if ( !load || f->second.is_set() ) {
return f->second; }
252 const std::string_view library = f->second.library;
257 std::stringstream ss;
258 if (
auto ptr = std::getenv(
"GAUDI_PLUGIN_PATH" ) ) ss << ptr;
261 while ( std::getline( ss, dir,
':' ) && !found ) {
262 if ( !fs::exists( dir ) ) {
continue; }
263 if ( is_regular_file( dir /
fs::path( library ) ) ) {
265 if ( !tryDLOpen( ( dir /
fs::path( library ) ).
string() ) ) {
273 if ( !found && !tryDLOpen( library ) )
return unknown;
274 f = facts.find(
id );
278 Registry& Registry::addProperty(
const KeyType&
id,
const KeyType& k,
const std::string&
v ) {
279 auto _guard = std::scoped_lock{ m_mutex };
281 auto f = facts.find(
id );
283 if ( f != facts.end() ) f->second.properties[k] =
v;
287 void Registry::setError(
const KeyType& warning ) { m_werror.insert( warning ); }
289 void Registry::unsetError(
const KeyType& warning ) { m_werror.erase( warning ); }
291 std::set<Registry::KeyType> Registry::loadedFactoryNames()
const {
292 auto _guard = std::scoped_lock{ m_mutex };
295 if ( f.second.is_set() )
l.insert( f.first );
300 void Logger::report(
Level lvl,
const std::string&
msg ) {
301 static const char* levels[] = {
"DEBUG : ",
"INFO : ",
"WARNING: ",
"ERROR : " };
302 if ( lvl >=
level() ) { std::cerr << levels[lvl] <<
msg << std::endl; }
305 static auto s_logger = std::make_unique<Logger>();
311 #if defined _GNU_SOURCE || defined __APPLE__
313 if ( dladdr( fptr, &info ) == 0 )
return "";
315 auto pos = std::strrchr( info.dli_fname,
'/' );
319 return info.dli_fname;
328 using namespace Details;
330 if ( debugLevel > 1 )
332 else if ( debugLevel > 0 )
333 l.setLevel( Logger::Info );
335 l.setLevel( Logger::Warning );
339 using namespace Details;