14 #define GAUDI_PLUGIN_SERVICE_V1
29 #define REG_SCOPE_LOCK std::lock_guard<std::recursive_mutex> _guard( m_mutex );
32 std::mutex registrySingletonMutex;
34 #define SINGLETON_LOCK std::lock_guard<std::mutex> _guard( ::registrySingletonMutex );
42 constexpr
struct is_space_t {
43 bool operator()(
int i )
const {
return std::isspace( i ); }
47 static inline std::string& ltrim( std::string& s ) {
48 s.erase( s.begin(), std::find_if_not( s.begin(), s.end(), is_space ) );
53 static inline std::string& rtrim( std::string& s ) {
54 s.erase( std::find_if_not( s.rbegin(), s.rend(), is_space ).base(), s.end() );
58 static inline std::string& trim( std::string& s ) {
return ltrim( rtrim( s ) ); }
65 inline void factoryInfoSetHelper( std::string& dest,
const std::string value,
const std::string& desc,
66 const std::string&
id ) {
69 }
else if ( dest != value ) {
71 ": " + dest +
" != " + value );
77 void operator()(
const char c ) {
86 name.push_back(
'_' );
89 name.push_back(
'r' );
92 name.push_back(
'p' );
103 std::string old_style_name(
const std::string& name ) {
104 return std::for_each( name.begin(), name.end(), OldStyleCnv() ).name;
109 namespace PluginService {
116 void*
getCreator(
const std::string&
id,
const std::string& type ) {
122 auto realname = std::unique_ptr<char, decltype( free )*>(
123 abi::__cxa_demangle(
id.c_str(),
nullptr,
nullptr, &status ), free );
124 if ( !realname )
return id;
125 #if _GLIBCXX_USE_CXX11_ABI
126 return std::regex_replace(
128 std::regex{
"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >( (?=>))?"},
131 return std::string{realname.get()};
148 #if defined( _WIN32 )
149 const char* envVar =
"PATH";
150 const char sep =
';';
151 #elif defined( __APPLE__ )
152 const char* envVar =
"DYLD_LIBRARY_PATH";
153 const char sep =
':';
155 const char* envVar =
"LD_LIBRARY_PATH";
156 const char sep =
':';
158 char* search_path = ::getenv( envVar );
160 logger().
debug( std::string(
"searching factories in " ) + envVar );
161 std::string path( search_path );
162 std::string::size_type pos = 0;
163 std::string::size_type newpos = 0;
164 while ( pos != std::string::npos ) {
167 newpos = path.find( sep, pos );
168 if ( newpos != std::string::npos ) {
169 dirName = path.substr( pos, newpos - pos );
172 dirName = path.substr( pos );
175 logger().
debug( std::string(
" looking into " ) + dirName );
177 DIR* dir = opendir( dirName.c_str() );
179 struct dirent* entry;
180 while ( ( entry = readdir( dir ) ) ) {
181 std::string name( entry->d_name );
183 std::string::size_type extpos = name.find(
".components" );
184 if ( ( extpos != std::string::npos ) && ( ( extpos + 11 ) == name.size() ) ) {
185 std::string fullPath = ( dirName +
'/' + name );
188 if ( 0 != ::stat( fullPath.c_str(), &buf ) )
190 else if ( !S_ISREG( buf.st_mode ) )
194 logger().
debug( std::string(
" reading " ) + name );
197 int factoriesCount = 0;
204 if ( line.empty() || line[0] ==
'#' )
continue;
206 if ( line.substr( 0, 4 ) ==
"v1::" )
207 line = line.substr( 4 );
211 auto pos = line.find(
':' );
212 if ( pos == std::string::npos ) {
213 logger().
warning(
"failed to parse line " + fullPath +
':' + std::to_string( lineCount ) );
216 const std::string lib( line, 0, pos );
217 const std::string fact( line, pos + 1 );
219 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
221 std::string old_name = old_style_name( fact );
222 if ( fact != old_name ) {
231 logger().
debug(
" found " + std::to_string( factoriesCount ) +
" factories" );
242 const std::string& rtype,
const std::string& className,
246 auto entry = facts.find(
id );
247 if ( entry == facts.end() ) {
249 entry = facts.emplace(
id,
FactoryInfo(
"unknown", factory, type, rtype, className, props ) ).first;
252 if ( !entry->second.ptr ) entry->second.ptr = factory;
253 factoryInfoSetHelper( entry->second.type, type,
"type",
id );
254 factoryInfoSetHelper( entry->second.rtype, rtype,
"return type",
id );
255 factoryInfoSetHelper( entry->second.className, className,
"class",
id );
257 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
259 std::string old_name = old_style_name(
id );
260 if (
id != old_name )
261 add( old_name, factory, type, rtype, className, props ).
properties[
"ReflexName"] =
"true";
263 return entry->second;
266 void*
Registry::get(
const std::string&
id,
const std::string& type )
const {
269 auto f = facts.find(
id );
270 if ( f != facts.end() ) {
271 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
272 const Properties& props = f->second.properties;
273 if ( props.find(
"ReflexName" ) != props.end() )
277 f->second.className +
"' instead" );
279 if ( !f->second.ptr ) {
280 if ( !dlopen( f->second.library.c_str(), RTLD_LAZY | RTLD_GLOBAL ) ) {
281 logger().
warning(
"cannot load " + f->second.library +
" for factory " +
id );
282 char* dlmsg = dlerror();
286 f = facts.find(
id );
288 if ( f->second.type == type )
return f->second.ptr;
290 " instead of " +
demangle( type ) );
299 auto f = facts.find(
id );
300 return ( f != facts.end() ) ? f->second : unknown;
306 auto f = facts.find(
id );
307 if ( f != facts.end() ) f->second.properties[k] =
v;
315 if ( f.second.ptr ) l.insert( f.first );
321 static const char* levels[] = {
"DEBUG : ",
"INFO : ",
"WARNING: ",
"ERROR : "};
322 if ( lvl >=
level() ) { std::cerr << levels[lvl] << msg << std::endl; }
325 static auto s_logger = std::make_unique<Logger>();
332 using namespace Details;
334 if ( debugLevel > 1 )
336 else if ( debugLevel > 0 )
343 using namespace Details;
344 switch (
logger().level() ) {