finished and documented
This commit is contained in:
@@ -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,6 +78,206 @@ namespace mrw {
|
||||
+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 / 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 / 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) {
|
||||
@@ -70,97 +311,12 @@ namespace mrw {
|
||||
private:
|
||||
lt_dlhandle _lib;
|
||||
};
|
||||
public:
|
||||
DynamicLibrary() throw(std::exception): _opened(false) {
|
||||
if (lt_dlinit()>0)
|
||||
throw failure("cannot initialize dynamic library loader");
|
||||
_opened = true;
|
||||
}
|
||||
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);
|
||||
}
|
||||
~DynamicLibrary() throw() {
|
||||
try {close();} catch (...) {}
|
||||
if (_opened) lt_dlexit();
|
||||
}
|
||||
DynamicLibrary& open(const std::string& lib) throw(std::exception) {
|
||||
_lib.open(lib);
|
||||
return *this;
|
||||
}
|
||||
DynamicLibrary& close() throw(std::exception) {
|
||||
_lib.close();
|
||||
return *this;
|
||||
}
|
||||
DynamicLibrary& resident() throw(std::exception) {
|
||||
if (lt_dlmakeresident(_lib.handle())!=0)
|
||||
throw failure("cannot make library resident");
|
||||
return *this;
|
||||
}
|
||||
bool isResident() throw(std::exception) {
|
||||
return lt_dlisresident(_lib.handle())==1;
|
||||
}
|
||||
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}
|
||||
*/
|
||||
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}
|
||||
*/
|
||||
DynamicLibrary& 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);
|
||||
}
|
||||
/// @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);
|
||||
// }
|
||||
static void addSearchDir(const std::string& dir) throw(std::exception) {
|
||||
if (lt_dladdsearchdir(dir.c_str())!=0)
|
||||
throw failure("cannot add search dir: "+dir);
|
||||
}
|
||||
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;
|
||||
// }
|
||||
private:
|
||||
bool _opened;
|
||||
Lib _lib;
|
||||
};
|
||||
|
||||
//@}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user