Commit 5f4d1e6f authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[ADD #296] functionality to load arbitrary extensions from a toolkit.

parent 3afc6ef7
......@@ -98,6 +98,19 @@ struct WSharedLib::data
return func_ptr;
}
/**
* Check for existence of a given function pointer symbol.
*
* \param name the symbol
*
* \return true if it exists.
*/
bool existsFunction( const std::string& name )
{
func_ptr_type func_ptr = reinterpret_cast< func_ptr_type >( GetProcAddress( m_hDLL, name.c_str() ) );
return func_ptr;
}
/**
* Searches the lib for the specified function symbol and returns it.
*
......@@ -217,24 +230,37 @@ struct WSharedLib::data
* Searches the lib for the specified symbol and returns it.
*
* \param name the name of the symbol to search.
* \param suppressThrow set to true to suppress the exception. NULL is returned if the symbol does not exists
*
* \return pointer to the symbol.
*
* \throw WLibraryFetchFailed thrown if the symbol could not be found.
*
*/
void* findVariable( const std::string& name )
void* findVariable( const std::string& name, bool suppressThrow = false )
{
auto_lock lock;
dlerror();
void* variable_ptr = dlsym( m_dl, name.c_str() );
const char *err = dlerror();
if( err )
if( !suppressThrow && err )
{
throw WLibraryFetchFailed( std::string( "Could not fetch symbol \"" + name + "\"" + " due to the error: " + err ) );
}
return variable_ptr;
}
/**
* Check for existence of a given function pointer symbol.
*
* \param name the symbol
*
* \return true if it exists.
*/
bool existsFunction( const std::string& name )
{
return findVariable( name, true );
}
};
#endif
......@@ -275,6 +301,11 @@ void* WSharedLib::findVariable( const std::string& name ) const
return m_data->findVariable( name );
}
bool WSharedLib::existsFunction( const std::string& name ) const
{
return m_data->existsFunction( name );
}
std::string WSharedLib::getSystemPrefix()
{
return W_LIB_PREFIX;
......
......@@ -99,6 +99,13 @@ public:
template < typename FuncType >
void fetchFunction( const std::string& name, FuncType& func ) const;
/**
* Check whether the function exists.
*
* \param name the name of the function
*/
bool existsFunction( const std::string& name ) const;
/** Search for an variable in the shared library
* \tparam PtrType a pointer type
* \param name the name of the variable
......
......@@ -766,6 +766,11 @@ typedef std::vector< boost::shared_ptr< WModule > > WModuleList;
*/
typedef void ( *W_LOADABLE_MODULE_SIGNATURE )( WModuleList& );
/**
* The signature used for the loaded toolbox as arbitrary registration function.
*/
typedef void ( *W_LOADABLE_REGISTERARBITRARY_SIGNATURE )( const boost::filesystem::path& );
/**
* The following macro is used by modules so the factory can acquire a prototype instance from a shared library using the symbol.
* You can write this symbol for your own if you need to add multiple modules to the list. This one is for convenience.
......@@ -781,6 +786,11 @@ extern "C" void WLoadModule( WModuleList& m ) { m.push_bac
*/
#define W_LOADABLE_MODULE_SYMBOL "WLoadModule"
/**
* THe register function's symbol name.
*/
#define W_LOADABLE_REGISTERARBITRARY_SYMBOL "WRegisterArbitrary"
/**
* \defgroup modules Modules
*
......
......@@ -82,44 +82,68 @@ void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_p
// load lib
boost::shared_ptr< WSharedLib > l = boost::shared_ptr< WSharedLib >( new WSharedLib( i->path() ) );
// get instantiation function
W_LOADABLE_MODULE_SIGNATURE f;
l->fetchFunction< W_LOADABLE_MODULE_SIGNATURE >( W_LOADABLE_MODULE_SYMBOL, f );
// get the first prototype
WModuleList m;
f( m );
bool isLoadableModule = false;
bool isLoadableArbitrary = false;
// could the prototype be created?
if( m.empty() )
// be nice. Do not fail if the module symbol does not exist
if( l->existsFunction( W_LOADABLE_MODULE_SYMBOL ) )
{
WLogger::getLogger()->addLogMessage( "Load failed for module \"" + relPath + "\". Could not create any " +
"prototype instance.", "Module Loader", LL_ERROR );
continue;
}
else
{
// yes, add it to the list of prototypes
for( WModuleList::const_iterator iter = m.begin(); iter != m.end(); ++iter )
// get instantiation function
W_LOADABLE_MODULE_SIGNATURE f;
l->fetchFunction< W_LOADABLE_MODULE_SIGNATURE >( W_LOADABLE_MODULE_SYMBOL, f );
isLoadableModule = true;
// get the first prototype
WModuleList m;
f( m );
// could the prototype be created?
if( m.empty() )
{
// which lib?
( *iter )->setLibPath( i->path() );
// we use the library name (excluding extension and optional lib prefix) as package name
( *iter )->setPackageName( libBaseName );
// resource path
( *iter )->setLocalPath( WPathHelper::getModuleResourcePath( i->path().parent_path(), ( *iter )->getPackageName() ) );
// add module
ticket->get().insert( *iter );
// we need to keep a reference to the lib
m_libs.push_back( l );
continue;
}
else
{
// yes, add it to the list of prototypes
for( WModuleList::const_iterator iter = m.begin(); iter != m.end(); ++iter )
{
// which lib?
( *iter )->setLibPath( i->path() );
// we use the library name (excluding extension and optional lib prefix) as package name
( *iter )->setPackageName( libBaseName );
// resource path
( *iter )->setLocalPath( WPathHelper::getModuleResourcePath( i->path().parent_path(), ( *iter )->getPackageName() ) );
// add module
ticket->get().insert( *iter );
// we need to keep a reference to the lib
m_libs.push_back( l );
}
wlog::debug( "Module Loader" ) << "Loaded " << m.size() << " modules from " << relPath;
}
wlog::debug( "Module Loader" ) << "Loaded " << m.size() << " modules from " << relPath;
}
// do the same for the arbitrary register functionality
// get instantiation function
if( l->existsFunction( W_LOADABLE_REGISTERARBITRARY_SYMBOL ) )
{
W_LOADABLE_REGISTERARBITRARY_SIGNATURE arbitraryRegister;
l->fetchFunction< W_LOADABLE_REGISTERARBITRARY_SIGNATURE >( W_LOADABLE_REGISTERARBITRARY_SYMBOL, arbitraryRegister );
isLoadableArbitrary = true;
// put together the right path and call function
arbitraryRegister( WPathHelper::getModuleResourcePath( i->path().parent_path(), libBaseName ) );
}
// lib gets closed if l looses focus
if( !isLoadableModule && !isLoadableArbitrary )
{
wlog::warn( "Module Loader" ) << "Library does neither contain a module nor another extension.";
}
}
catch( const WException& e )
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment