Skip to content

Commit

Permalink
libdeng2|Mac OS X: Attempting to fix dynamic library loading issue
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
skyjake committed Oct 29, 2012
1 parent b8f17b8 commit fdc73ef
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 48 deletions.
13 changes: 3 additions & 10 deletions doomsday/libdeng2/include/de/core/library.h
Expand Up @@ -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.
Expand Down Expand Up @@ -204,15 +204,8 @@ namespace de
}

private:
/// Handle to the shared library.
QLibrary* _library;

typedef QMap<String, void*> 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;
};
}

Expand Down
129 changes: 91 additions & 38 deletions doomsday/libdeng2/src/core/library.cpp
Expand Up @@ -17,42 +17,75 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/

#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 <dlfcn.h>
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<String, void*> 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);
Expand All @@ -61,50 +94,65 @@ 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)();
}
}

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)
{
Expand All @@ -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
}

0 comments on commit fdc73ef

Please sign in to comment.