diff --git a/mrw/dynamiclibrary.hpp b/mrw/dynamiclibrary.hpp
index 6cec2b5..ad45fc1 100644
--- a/mrw/dynamiclibrary.hpp
+++ b/mrw/dynamiclibrary.hpp
@@ -9,6 +9,9 @@
@license LGPL, see file COPYING
$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 info libtool
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
+
+ @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(), "")) {
}
};
- 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