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
52 void operator()(
const char c ) {
61 name.push_back(
'_' );
64 name.push_back(
'r' );
67 name.push_back(
'p' );
84 namespace PluginService {
90 abi::__cxa_demangle(
id.c_str(),
nullptr,
nullptr, &status ), free );
91 if ( !realname )
return id;
94 std::regex{
"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >( (?=>))?" },
99 Registry& Registry::instance() {
100 auto _guard = std::scoped_lock{ ::registrySingletonMutex };
108 const auto& info = Registry::instance().getInfo(
id );
109 msg <<
"bad any_cast: requested factory " <<
id <<
" of type " <<
demangle( factory_type ) <<
", got ";
111 msg <<
demangle( info.factory.type() ) <<
" from " << info.library;
118 Registry::Properties::mapped_type Registry::FactoryInfo::getprop(
const Properties::key_type&
name )
const {
120 return ( p !=
end(
properties ) ) ? p->second : Properties::mapped_type{};
123 Registry::Registry() {}
125 void Registry::initialize() {
126 auto _guard = std::scoped_lock{ m_mutex };
127 #if defined( _WIN32 )
128 const char* envVar =
"PATH";
129 const char sep =
';';
130 #elif defined( __APPLE__ )
131 const char* envVar =
"GAUDI_PLUGIN_PATH";
132 const char sep =
':';
134 const char* envVar =
"LD_LIBRARY_PATH";
135 const char sep =
':';
138 std::regex line_format{
"^(?:[[:space:]]*(?:(v[0-9]+)::)?([^:]+):(.*[^[:space:]]))?[[:space:]]*(?:#.*)?$" };
141 std::string_view search_path;
142 if (
auto ptr =
std::getenv( envVar ) ) search_path = std::string_view{ ptr };
143 if ( !search_path.empty() ) {
146 std::string_view::size_type start_pos = 0, end_pos = 0;
147 while ( start_pos != std::string_view::npos ) {
149 if ( start_pos ) ++start_pos;
151 end_pos = search_path.find( sep, start_pos );
153 #ifdef USE_BOOST_FILESYSTEM
156 search_path.substr( start_pos, end_pos - start_pos );
159 logger().debug(
" looking into " + dirName.string() );
161 if ( is_directory( dirName ) ) {
162 for (
auto& p : fs::directory_iterator( dirName ) ) {
163 if ( p.path().extension() ==
".components" && is_regular_file( p.path() ) ) {
165 const auto& fullPath = p.path().string();
166 logger().debug(
" reading " + p.path().filename().string() );
169 int factoriesCount = 0;
175 if (
m[1] ==
"v2" ) {
178 m_factories.emplace( fact, FactoryInfo{ lib, {}, { {
"ClassName", fact } } } );
179 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
182 if ( fact != old_name ) {
184 old_name, FactoryInfo{ lib, {}, { {
"ReflexName",
"true" }, {
"ClassName", fact } } } );
204 std::call_once( m_initialized, &Registry::initialize,
const_cast<Registry*
>(
this ) );
213 Registry::FactoryInfo&
Registry::add(
const KeyType&
id, FactoryInfo info ) {
214 auto _guard = std::scoped_lock{ m_mutex };
217 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
219 const auto old_name = old_style_name(
id );
220 if (
id != old_name ) {
221 auto new_info = info;
223 new_info.properties[
"ReflexName"] =
"true";
225 add( old_name, new_info );
229 auto entry = facts.find(
id );
230 if ( entry == facts.end() ) {
232 entry = facts.emplace(
id,
std::move( info ) ).first;
235 if ( !entry->second.is_set() ) entry->second =
std::move( info );
237 return entry->second;
240 Registry::FactoryMap::size_type Registry::erase(
const KeyType&
id ) {
241 auto _guard = std::scoped_lock{ m_mutex };
243 return facts.erase(
id );
246 const Registry::FactoryInfo& Registry::getInfo(
const KeyType&
id,
const bool load )
const {
247 auto _guard = std::scoped_lock{ m_mutex };
248 static const FactoryInfo unknown = {
"unknown" };
250 auto f = facts.find(
id );
252 if ( f != facts.end() ) {
253 if ( load && !f->second.is_set() ) {
256 std::string_view search_path;
257 if (
auto ptr =
std::getenv(
"GAUDI_PLUGIN_PATH" ) ) search_path = std::string_view{ ptr };
258 if ( !search_path.empty() ) {
260 std::string_view::size_type start_pos = 0, end_pos = 0;
261 while ( start_pos != std::string_view::npos ) {
263 if ( start_pos ) ++start_pos;
265 end_pos = search_path.
find(
":", start_pos );
267 # ifdef USE_BOOST_FILESYSTEM
270 search_path.substr( start_pos, end_pos - start_pos );
274 logger().debug(
" looking into " + dirName.string() );
276 if ( is_directory( dirName ) && is_regular_file( dirName /
fs::path( library ) ) ) {
277 logger().debug(
"found " + dirName.string() +
"/" + library.
c_str() +
" for factory " +
id );
278 if ( !dlopen( ( dirName.string() +
"/" + library ).c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
279 logger().warning(
"cannot load " + library +
" for factory " +
id );
280 char* dlmsg = dlerror();
281 if ( dlmsg )
logger().warning( dlmsg );
289 if ( !dlopen( library.
c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
290 logger().warning(
"cannot load " + library +
" for factory " +
id );
291 char* dlmsg = dlerror();
292 if ( dlmsg )
logger().warning( dlmsg );
296 f = facts.find(
id );
304 Registry& Registry::addProperty(
const KeyType&
id,
const KeyType& k,
const std::string&
v ) {
305 auto _guard = std::scoped_lock{ m_mutex };
307 auto f = facts.find(
id );
309 if ( f != facts.end() ) f->second.properties[k] =
v;
313 void Registry::setError(
const KeyType& warning ) { m_werror.insert( warning ); }
315 void Registry::unsetError(
const KeyType& warning ) { m_werror.erase( warning ); }
318 auto _guard = std::scoped_lock{ m_mutex };
321 if ( f.second.is_set() )
l.insert( f.first );
327 static const char* levels[] = {
"DEBUG : ",
"INFO : ",
"WARNING: ",
"ERROR : " };
331 static auto s_logger = std::make_unique<Logger>();
337 #if defined _GNU_SOURCE || defined __APPLE__
339 if ( dladdr( fptr, &info ) == 0 )
return "";
345 return info.dli_fname;
354 using namespace Details;
356 if ( debugLevel > 1 )
358 else if ( debugLevel > 0 )
359 l.setLevel( Logger::Info );
361 l.setLevel( Logger::Warning );
365 using namespace Details;