From ad44ffdf1bfd5662a8e1f7543d0d4846bcf78789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Mon, 21 Feb 2005 16:16:47 +0000 Subject: [PATCH] finished and documented --- mrw/dynamiclibrary.hpp | 330 ++++++++++++++++++++++++++++++----------- 1 file changed, 243 insertions(+), 87 deletions(-) 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,6 +78,206 @@ namespace mrw { +mrw::ifelse(lt_dlerror(), "")) { } }; + + //................................................................ 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