|
|
|
@ -9,6 +9,9 @@ |
|
|
|
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
|
|
|
|
|
|
$Log$ |
|
|
|
|
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 |
|
|
|
|
|
|
|
|
@ -27,8 +30,46 @@ |
|
|
|
|
|
|
|
|
|
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 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 / 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): |
|
|
|
@ -37,45 +78,32 @@ namespace mrw { |
|
|
|
|
+mrw::ifelse(lt_dlerror(), "<none>")) { |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
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; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//................................................................ 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 / 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) |
|
|
|
@ -83,84 +111,212 @@ namespace mrw { |
|
|
|
|
_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 / 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) { |
|
|
|
|
_lib.close(); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
/**
|
|
|
|
|
{{"name1", &name1}, {"name2", &name2}, 0} |
|
|
|
|
|
|
|
|
|
/** 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) |
|
|
|
|
DynamicLibrary& preload(const lt_dlsymlist symbols[]) |
|
|
|
|
throw(std::exception) { |
|
|
|
|
if (lt_dlpreload(symbols)!=0) |
|
|
|
|
throw failure("error in preloading libraries"); |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
/**
|
|
|
|
|
{{"name1", &name1}, {"name2", &name2}, 0} |
|
|
|
|
|
|
|
|
|
/** 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 |
|
|
|
|
*/ |
|
|
|
|
DynamicLibrary& preloadDefault(const lt_dlsymlist* symbols) |
|
|
|
|
static void preloadDefault(const lt_dlsymlist symbols[]) |
|
|
|
|
throw(std::exception) { |
|
|
|
|
if (lt_dlpreload_default(symbols)!=0) |
|
|
|
|
throw failure("error in preloading libraries"); |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
int foreachfile(const char* searchPath, |
|
|
|
|
int(*function)(const char*, lt_ptr), |
|
|
|
|
lt_ptr data) throw() { |
|
|
|
|
return lt_dlforeachfile(searchPath, function, data); |
|
|
|
|
|
|
|
|
|
/** @brief set the default list of preloaded symbols */ |
|
|
|
|
static void preloadedSymbols() throw(std::bad_exception) { |
|
|
|
|
LTDL_SET_PRELOADED_SYMBOLS(); |
|
|
|
|
} |
|
|
|
|
/// @todo enable
|
|
|
|
|
// static void preloadedSymbols(const std::string& lib,
|
|
|
|
|
// const lt_dlsymlist symbols[])
|
|
|
|
|
// throw(std::exception) {
|
|
|
|
|
// Lib lib(lt_dlopenext(lib.c_str()));
|
|
|
|
|
// LTDL_SET_PRELOADED_SYMBOLS(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); |
|
|
|
|
} |
|
|
|
|
/// @todo enable
|
|
|
|
|
// static std::string void setSearchPath(const std::string& dir) throw() {
|
|
|
|
|
// char const * const path(lt_dlgetsearchpath());
|
|
|
|
|
// if (!path)
|
|
|
|
|
// throw failure("cannot get search path");
|
|
|
|
|
// return path;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
/** @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 |
|
|
|
|