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