// NeL - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "stdmisc.h"
#include "nel/misc/dynloadlib.h"
#include "nel/misc/path.h"
using namespace std;
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
namespace NLMISC
{
NL_LIB_HANDLE nlLoadLibrary(const std::string &libName)
{
NL_LIB_HANDLE res = 0;
#ifdef NL_OS_WINDOWS
res = LoadLibrary(libName.c_str());
#elif defined(NL_OS_UNIX)
res = dlopen(libName.c_str(), RTLD_NOW);
#else
# error "You must code nlLoadLibrary() for your platform"
#endif
if(res == 0) nlwarning("Load library '%s' failed: %s", libName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
return res;
}
bool nlFreeLibrary(NL_LIB_HANDLE libHandle)
{
#ifdef NL_OS_WINDOWS
return FreeLibrary(libHandle) > 0;
#elif defined(NL_OS_UNIX)
return dlclose(libHandle) == 0;
#else
# error "You must code nlFreeLibrary() for your platform"
#endif
}
void *nlGetSymbolAddress(NL_LIB_HANDLE libHandle, const std::string &procName)
{
void *res = 0;
#ifdef NL_OS_WINDOWS
res = (void *)GetProcAddress(libHandle, procName.c_str());
#elif defined(NL_OS_UNIX)
res = dlsym(libHandle, procName.c_str());
#else
# error "You must code nlGetProcAddress() for your platform"
#endif
if(res == 0) nlwarning("Getting symbol address of '%s' failed: %s", procName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
return res;
}
// Again some OS specifics stuff
#ifdef NL_OS_WINDOWS
const string nlLibPrefix; // empty
const string nlLibExt(".dll");
#elif defined(NL_OS_MAC)
const string nlLibPrefix("lib");
const string nlLibExt(".dylib");
#elif defined(NL_OS_UNIX)
const string nlLibPrefix("lib");
const string nlLibExt(".so");
#else
# error "You must define the default dynamic lib extention"
#endif
std::vector CLibrary::_LibPaths;
CLibrary::CLibrary (const CLibrary &/* other */)
{
// Nothing to do has it is forbidden.
// Allowing copy require to manage reference count from CLibrary to the module resource.
nlassert(false);
}
CLibrary &CLibrary::operator =(const CLibrary &/* other */)
{
// Nothing to do has it is forbidden.
// Allowing assignment require to manage reference count from CLibrary to the module resource.
nlassert(false);
return *this;
}
std::string CLibrary::makeLibName(const std::string &baseName)
{
return nlLibPrefix+baseName+nlLibSuffix+nlLibExt;
}
std::string CLibrary::cleanLibName(const std::string &decoratedName)
{
// remove path and extension
string ret = CFile::getFilenameWithoutExtension(decoratedName);
if (!nlLibPrefix.empty())
{
// remove prefix
if (ret.find(nlLibPrefix) == 0)
ret = ret.substr(nlLibPrefix.size());
}
if (!nlLibSuffix.empty())
{
// remove suffix
if (ret.substr(ret.size()-nlLibSuffix.size()) == nlLibSuffix)
ret = ret.substr(0, ret.size() - nlLibSuffix.size());
}
return ret;
}
void CLibrary::addLibPaths(const std::vector &paths)
{
for (uint i=0; i(entryPoint));
// call the private initialization method.
_PureNelLibrary->_onLibraryLoaded(INelContext::getInstance());
}
}
return _LibHandle != NULL;
}
void CLibrary::freeLibrary()
{
if (_LibHandle)
{
nlassert(_Ownership);
if (_PureNelLibrary)
{
// call the private finalization method.
_PureNelLibrary->_onLibraryUnloaded();
}
nldebug("Freeing dynamic library '%s'", _LibFileName.c_str());
nlFreeLibrary(_LibHandle);
_PureNelLibrary = NULL;
_LibHandle = NULL;
_Ownership = false;
_LibFileName = "";
}
}
void *CLibrary::getSymbolAddress(const std::string &symbolName)
{
nlassert(_LibHandle != NULL);
return nlGetSymbolAddress(_LibHandle, symbolName);
}
bool CLibrary::isLibraryLoaded()
{
return _LibHandle != NULL;
}
bool CLibrary::isLibraryPure()
{
return _LibHandle != NULL && _PureNelLibrary != NULL;
}
INelLibrary *CLibrary::getNelLibraryInterface()
{
if (!isLibraryPure())
return NULL;
return _PureNelLibrary;
}
INelLibrary::~INelLibrary()
{
// cleanup ram
if (_LibContext != NULL)
delete _LibContext;
}
void INelLibrary::_onLibraryLoaded(INelContext &nelContext)
{
++_LoadingCounter;
if (_LoadingCounter == 1)
{
// Linux relocates all symbols, so this is unnecessary.
#ifdef NL_OS_WINDOWS
// initialize NeL context
nlassert(!NLMISC::INelContext::isContextInitialised());
#endif // NL_OS_WINDOWS
_LibContext = new CLibraryContext(nelContext);
}
else
{
nlassert(NLMISC::INelContext::isContextInitialised());
}
onLibraryLoaded(_LoadingCounter==1);
}
void INelLibrary::_onLibraryUnloaded()
{
nlassert(_LoadingCounter > 0);
onLibraryUnloaded(_LoadingCounter == 1);
--_LoadingCounter;
}
uint32 INelLibrary::getLoadingCounter()
{
return _LoadingCounter;
}
} // namespace NLMISC