From fdc73ef3fa936ac6addd265e1a2ced726a7bb4b9 Mon Sep 17 00:00:00 2001 From: skyjake Date: Mon, 29 Oct 2012 18:10:55 +0200 Subject: [PATCH] libdeng2|Mac OS X: Attempting to fix dynamic library loading issue With Qt 4.7 (in the 10.6+ build), returned to the native dlopen() for loading the libraries instead of QLibrary, which seems to be doing something strange when the library is being unloaded. --- doomsday/libdeng2/include/de/core/library.h | 13 +- doomsday/libdeng2/src/core/library.cpp | 129 ++++++++++++++------ 2 files changed, 94 insertions(+), 48 deletions(-) diff --git a/doomsday/libdeng2/include/de/core/library.h b/doomsday/libdeng2/include/de/core/library.h index 4d8c4c056b..6825a5152c 100644 --- a/doomsday/libdeng2/include/de/core/library.h +++ b/doomsday/libdeng2/include/de/core/library.h @@ -138,7 +138,7 @@ namespace de * automatically when the library is first loaded, and can then be * queried at any time even after the library has been unloaded. */ - const String& type() const { return _type; } + const String& type() const; enum SymbolLookupMode { RequiredSymbol, ///< Symbol must be exported. @@ -204,15 +204,8 @@ namespace de } private: - /// Handle to the shared library. - QLibrary* _library; - - typedef QMap Symbols; - Symbols _symbols; - - /// Type identifier for the library (e.g., "deng-plugin/generic"). - /// Queried by calling deng_LibraryType(), if one is exported in the library. - String _type; + struct Instance; + Instance* d; }; } diff --git a/doomsday/libdeng2/src/core/library.cpp b/doomsday/libdeng2/src/core/library.cpp index 3c3a399c3d..4d59f0251e 100644 --- a/doomsday/libdeng2/src/core/library.cpp +++ b/doomsday/libdeng2/src/core/library.cpp @@ -17,42 +17,75 @@ * along with this program; if not, see . */ +#include "de/libdeng2.h" #include "de/Library" #include "de/Log" +#if defined(UNIX) && defined(DENG2_QT_4_7_OR_NEWER) && !defined(DENG2_QT_4_8_OR_NEWER) +# define DENG2_USE_DLOPEN +# include +typedef void* Handle; +#else +typedef QLibrary* Handle; +#endif + using namespace de; const char* Library::DEFAULT_TYPE = "library/generic"; -Library::Library(const String& nativePath) - : _library(0), _type(DEFAULT_TYPE) +struct Library::Instance +{ + /// Handle to the shared library. + Handle library; + + typedef QMap Symbols; + Symbols symbols; + + /// Type identifier for the library (e.g., "deng-plugin/generic"). + /// Queried by calling deng_LibraryType(), if one is exported in the library. + String type; + + Instance() : library(0), type(DEFAULT_TYPE) + {} + +#ifdef DENG2_USE_DLOPEN + String fileName; + String nativePath() { return fileName; } + bool isLoaded() const { return library != 0; } +#else + String nativePath() { + DENG2_ASSERT(library); + return library->fileName(); + } + bool isLoaded() const { return library->isLoaded(); } +#endif +}; + +Library::Library(const String& nativePath) : d(0) { + d = new Instance; + LOG_AS("Library::Library"); LOG_TRACE("Loading ") << nativePath; - /* -#ifdef MACOSX - // If the library happens to be in a bundle, just use the bundle path. - String path = nativePath; - if(path.fileNamePath().fileNameExtension() == ".bundle") - { - path = path; //.fileNamePath().fileNameWithoutExtension(); - } - LOG_TRACE("%s") << path; - _library = new QLibrary(path); -#else*/ - LOG_TRACE("%s") << nativePath; - _library = new QLibrary(nativePath); -//#endif - _library->setLoadHints(QLibrary::ResolveAllSymbolsHint); - _library->load(); - - if(!_library->isLoaded()) - { - QString msg = _library->errorString(); +#ifndef DENG2_USE_DLOPEN + d->library = new QLibrary(nativePath); + d->library->setLoadHints(QLibrary::ResolveAllSymbolsHint); + d->library->load(); +#else + d->fileName = nativePath; + d->library = dlopen(nativePath.toUtf8().constData(), RTLD_NOW); +#endif - delete _library; - _library = 0; + if(!d->isLoaded()) + { +#ifndef DENG2_USE_DLOPEN + QString msg = d->library->errorString(); + delete d->library; +#else + QString msg = dlerror(); +#endif + d->library = 0; /// @throw LoadError Opening of the dynamic library failed. throw LoadError("Library::Library", msg); @@ -61,11 +94,11 @@ Library::Library(const String& nativePath) if(hasSymbol("deng_LibraryType")) { // Query the type identifier. - _type = DENG2_SYMBOL(deng_LibraryType)(); + d->type = DENG2_SYMBOL(deng_LibraryType)(); } // Automatically call the initialization function, if one exists. - if(_type.beginsWith("deng-plugin/") && hasSymbol("deng_InitializePlugin")) + if(d->type.beginsWith("deng-plugin/") && hasSymbol("deng_InitializePlugin")) { DENG2_SYMBOL(deng_InitializePlugin)(); } @@ -73,38 +106,53 @@ Library::Library(const String& nativePath) Library::~Library() { - if(_library) + if(d->library) { LOG_AS("Library::~Library"); - LOG_TRACE("Unlading ") << _library->fileName(); + LOG_TRACE("Unloading ") << d->nativePath(); // Automatically call the shutdown function, if one exists. - if(_type.beginsWith("deng-plugin/") && hasSymbol("deng_ShutdownPlugin")) + if(d->type.beginsWith("deng-plugin/") && hasSymbol("deng_ShutdownPlugin")) { DENG2_SYMBOL(deng_ShutdownPlugin)(); } - _library->unload(); - delete _library; +#ifndef DENG2_USE_DLOPEN + d->library->unload(); + delete d->library; +#else + dlclose(d->library); +#endif } + + delete d; +} + +const String &Library::type() const +{ + return d->type; } void* Library::address(const String& name, SymbolLookupMode lookup) { - if(!_library) + if(!d->library) { /// @throw SymbolMissingError There is no library loaded at the moment. throw SymbolMissingError("Library::symbol", "Library not loaded"); } // Already looked up? - Symbols::iterator found = _symbols.find(name); - if(found != _symbols.end()) + Instance::Symbols::iterator found = d->symbols.find(name); + if(found != d->symbols.end()) { return found.value(); } - void* ptr = _library->resolve(name.toAscii().constData()); +#ifndef DENG2_USE_DLOPEN + void* ptr = d->library->resolve(name.toAscii().constData()); +#else + void* ptr = dlsym(d->library, name.toAscii().constData()); +#endif if(!ptr) { @@ -116,13 +164,18 @@ void* Library::address(const String& name, SymbolLookupMode lookup) return 0; } - _symbols[name] = ptr; + d->symbols[name] = ptr; return ptr; } bool Library::hasSymbol(const String &name) const { // First check the symbols cache. - if(_symbols.find(name) != _symbols.end()) return true; - return _library->resolve(name.toAscii().constData()) != 0; + if(d->symbols.find(name) != d->symbols.end()) return true; + +#ifndef DENG2_USE_DLOPEN + return d->library->resolve(name.toAscii().constData()) != 0; +#else + return dlsym(d->library, name.toAscii().constData()) != 0; +#endif }