/** @file
$ Id $
$ Date $
$ Author $
@ copy & copy ; Marc W & auml ; ckerlin
@ license LGPL , see file < a href = " license.html " > COPYING < / a >
$ Log $
Revision 1.3 2005 / 11 / 29 12 : 39 : 42 marc
make it compilable with gcc 4.0 .2 and newer doxygen
Revision 1.2 2005 / 02 / 21 16 : 16 : 47 marc
finished and documented
Revision 1.1 2005 / 02 / 18 15 : 53 : 56 marc
initial release
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
# ifndef __MRW_DYNAMICLIBRARY_HPP__
# define __MRW_DYNAMICLIBRARY_HPP__
# include <ltdl.h>
# include <mrw/string.hpp>
# include <mrw/stdext.hpp>
# include <mrw/exception.hpp>
namespace mrw {
/** @defgroup dll Dynamic Library Loading (ltdl)
Implements a C + + wrapper around the Libtool ' s
platform independent dynamic library loading library named
libltdl . See < code > info & nbsp ; libtool < / code > for more
information .
Loading a symbol from a shared library :
@ code
void fn ( ) throw ( mrw : : DynamicLibrary : : failure ) {
static DynamicLibrary lib ( " libsomething " ) ;
static void ( * theRealFunction ) ( ) =
( void ( * ) ( ) ) lib . symbol ( " theRealFunction " ) ;
( * theRealFunction ) ( ) ; // call the loaded function
}
@ endcode
@ pre \ # include < mrw / dynamiclibrary . hpp >
@ pre Files that use this wrapper must be linked with libltdl ,
with GNU g + + on UNIX , this is link option : @ c - lltdl
*/
//@{
//============================================================================
/** @brief Dynamic Library loaded from the filesystem at runtime.
This class is responsible for loading dynamic & nbsp ; / shared
libraries from the filesystem and extract symbols , means
functions to assign them to function pointers that can then be
accessed .
@ copydoc dll
*/
class DynamicLibrary {
//............................................................... typedefs
public :
/// failure in access to shared libraries
class failure : public mrw : : runtime_error {
public :
failure ( const std : : string & arg ) throw ( std : : bad_exception ) :
mrw : : runtime_error ( " DynamicLibrary failure " + arg
+ " ; ltdl reason: " +
+ mrw : : ifelse ( lt_dlerror ( ) , " <none> " ) ) {
}
} ;
//................................................................ methods
public :
/** @brief initialize, but open dynamic library later
@ throw failure if initialisation fails
*/
DynamicLibrary ( ) throw ( std : : exception ) : _opened ( false ) {
if ( lt_dlinit ( ) > 0 )
throw failure ( " cannot initialize dynamic library loader " ) ;
_opened = true ;
}
/** @brief load a dynamic library from a file
It is not necessary to specify the extension , the system
dependant shared object & nbsp ; / dynamic library extension is
automatically added . Also , if no path is given , the library
is automatically looked for in your system ' s library
paths . You can also specify additional paths to look in ,
e . g . with addSearchDir .
@ param lib the name of the library without the extension
@ throw failure if initialisation fails
@ throw failure if opeing the library fails
*/
DynamicLibrary ( const std : : string & lib ) throw ( std : : exception ) :
_opened ( false ) {
if ( lt_dlinit ( ) > 0 )
throw failure ( " cannot initialize dynamic library loader " ) ;
_opened = true ;
_lib . open ( lib ) ;
}
/// close and clean up
~ DynamicLibrary ( ) throw ( ) {
try { close ( ) ; } catch ( . . . ) { }
if ( _opened ) lt_dlexit ( ) ;
}
/** @brief load a dynamic library from a file
It is not necessary to specify the extension , the system
dependant shared object & nbsp ; / dynamic library extension is
automatically added . Also , if no path is given , the library
is automatically looked for in your system ' s library
paths . You can also specify additional paths to look in ,
e . g . with addSearchDir .
@ param lib the name of the library without the extension
@ throw failure if opeing the library fails
*/
DynamicLibrary & open ( const std : : string & lib ) throw ( std : : exception ) {
_lib . open ( lib ) ;
return * this ;
}
/** @brief close the dynamic library
@ throw failure if the library was open and close failed
*/
DynamicLibrary & close ( ) throw ( std : : exception ) {
if ( ! isResident ( ) ) _lib . close ( ) ;
return * this ;
}
/** @brief make the library resident
Makes the library resident , so that it cannot be
closed . This can be useful if a module implements some core
functionality in your project , which would cause your code
to crash if removed .
@ throw failure in case of an error
*/
DynamicLibrary & resident ( ) throw ( std : : exception ) {
if ( lt_dlmakeresident ( _lib . handle ( ) ) ! = 0 )
throw failure ( " cannot make library resident " ) ;
return * this ;
}
/** @brief check whether the library is resident
@ throw failure if the library is not open */
bool isResident ( ) throw ( std : : exception ) {
return lt_dlisresident ( _lib . handle ( ) ) = = 1 ;
}
/** @brief load a symbol from the library
@ warning The symbol is returned as void * and must be
converted to the correct function pointer . If this
conversion is wrong , then your process will crash , or even
worse , behave in an unexpected way , so be careful !
*/
lt_ptr symbol ( const std : : string & name ) throw ( std : : exception ) {
lt_ptr sym ( lt_dlsym ( _lib . handle ( ) , name . c_str ( ) ) ) ;
if ( ! sym )
throw failure ( " cannot load dynamic library symbol: " + name ) ;
return sym ;
}
/** register a list of preloaded modules
@ code
const lt_dlsymlist symbols [ ] = {
{ " symbol1 " , & fnptr1 } , { " symbol2 " , & fnptr2 } , 0
}
lib . preload ( symbols ) ;
@ endcode
@ param symbols a null terminated C array of structs of name
character pointer and function pointer
@ note if symbols is @ c 0 , all previousely registered
symbols except the list set by preloadDefault are deleted
*/
DynamicLibrary & preload ( const lt_dlsymlist symbols [ ] )
throw ( std : : exception ) {
if ( lt_dlpreload ( symbols ) ! = 0 )
throw failure ( " error in preloading libraries " ) ;
return * this ;
}
/** register the default list of preloaded modules
@ code
const lt_dlsymlist symbols [ ] = {
{ " symbol1 " , & fnptr1 } , { " symbol2 " , & fnptr2 } , 0
}
lib . preloadDefault ( symbols ) ;
@ endcode
@ param symbols a null terminated C array of structs of name
character pointer and function pointer
*/
static void preloadDefault ( const lt_dlsymlist symbols [ ] )
throw ( std : : exception ) {
if ( lt_dlpreload_default ( symbols ) ! = 0 )
throw failure ( " error in preloading libraries " ) ;
}
/** @brief set the default list of preloaded symbols */
static void preloadedSymbols ( ) throw ( std : : bad_exception ) {
LTDL_SET_PRELOADED_SYMBOLS ( ) ;
}
/** @brief append a directory to the library search path */
static void addSearchDir ( const std : : string & dir ) throw ( std : : exception ) {
if ( lt_dladdsearchdir ( dir . c_str ( ) ) ! = 0 )
throw failure ( " cannot add search dir: " + dir ) ;
}
/** @brief insert a directory at a given position to the library
search path */
static void insertSearchDir ( const std : : string & before ,
const std : : string & dir )
throw ( std : : exception ) {
if ( lt_dlinsertsearchdir ( before . c_str ( ) , dir . c_str ( ) ) ! = 0 )
throw failure ( " cannot add search dir: " + dir ) ;
}
/** @brief set the library search path
The search path is a colon separated list of paths . */
static void setSearchPath ( const std : : string & dirs ) throw ( ) {
if ( lt_dlsetsearchpath ( dirs . c_str ( ) ) )
throw failure ( " cannot set search path to " + dirs ) ;
}
/** @brief get the library search path */
static std : : string getSearchPath ( ) throw ( ) {
char const * const path ( lt_dlgetsearchpath ( ) ) ;
if ( ! path )
throw failure ( " cannot get search path " ) ;
return path ;
}
/** @brief calls a callback function for all directories in a
search path
In some applications you may not want to load individual
modules with known names , but rather find all of the modules
in a set of directories and load them all during
initialisation . With this function you can have
DynamicLibrary scan the colon delimited directory list in
searchPath for candidates , and pass them , along with data to
your own callback function , function . If searchPath is @ c 0 ,
then search all of the standard locations that open would
examine . This function will continue to make calls to
function for each file that it discovers in searchPath until
one of these calls returns non - zero , or until the files are
exhausted .
@ return value returned by the last call made to function
*/
int foreachfile ( const char * searchPath ,
int ( * function ) ( const char * , lt_ptr ) ,
lt_ptr data ) throw ( ) {
return lt_dlforeachfile ( searchPath , function , data ) ;
}
private :
class Lib {
Lib ( ) throw ( ) : _lib ( 0 ) { }
Lib ( const std : : string & lib ) throw ( std : : exception ) : _lib ( 0 ) {
open ( lib ) ;
}
~ Lib ( ) throw ( ) {
try { close ( ) ; } catch ( . . . ) { }
}
operator bool ( ) throw ( ) {
return _lib ;
}
Lib & open ( const std : : string & lib ) throw ( std : : exception ) {
close ( ) ;
if ( ! ( _lib = lt_dlopenext ( lib . c_str ( ) ) ) )
throw failure ( " cannot open dynamic library " + lib ) ;
return * this ;
}
Lib & close ( ) throw ( std : : exception ) {
if ( _lib & & lt_dlclose ( _lib ) ! = 0 )
throw failure ( " cannot close dynamic library " ) ;
_lib = 0 ;
return * this ;
}
private :
friend class DynamicLibrary ;
lt_dlhandle handle ( ) throw ( std : : exception ) {
if ( ! _lib )
throw failure ( " library not open " ) ;
return _lib ;
}
private :
lt_dlhandle _lib ;
} ;
private :
bool _opened ;
Lib _lib ;
} ;
//@}
}
# endif