Merge branch '138-toggle-free-look-with-hotkey' into 'main/atys-live'
[ryzomcore.git] / nel / src / misc / dynloadlib.cpp
blob8fe8a4227f1ef9949c33dac81fe8aebd706ab7d1
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdmisc.h"
22 #include "nel/misc/dynloadlib.h"
23 #include "nel/misc/path.h"
25 using namespace std;
27 #ifdef DEBUG_NEW
28 #define new DEBUG_NEW
29 #endif
31 namespace NLMISC
34 NL_LIB_HANDLE nlLoadLibrary(const std::string &libName)
36 NL_LIB_HANDLE res = 0;
37 #ifdef NL_OS_WINDOWS
38 res = LoadLibraryW(nlUtf8ToWide(libName));
39 #elif defined(NL_OS_UNIX)
40 res = dlopen(libName.c_str(), RTLD_NOW);
41 #else
42 # error "You must code nlLoadLibrary() for your platform"
43 #endif
44 if(res == 0) nlwarning("Load library '%s' failed: %s", libName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
45 return res;
48 bool nlFreeLibrary(NL_LIB_HANDLE libHandle)
50 #ifdef NL_OS_WINDOWS
51 return FreeLibrary(libHandle) > 0;
52 #elif defined(NL_OS_UNIX)
53 return dlclose(libHandle) == 0;
54 #else
55 # error "You must code nlFreeLibrary() for your platform"
56 #endif
59 void *nlGetSymbolAddress(NL_LIB_HANDLE libHandle, const std::string &procName)
61 void *res = 0;
62 #ifdef NL_OS_WINDOWS
63 res = (void *)GetProcAddress(libHandle, procName.c_str());
64 #elif defined(NL_OS_UNIX)
65 res = dlsym(libHandle, procName.c_str());
66 #else
67 # error "You must code nlGetProcAddress() for your platform"
68 #endif
69 if(res == 0) nlwarning("Getting symbol address of '%s' failed: %s", procName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
70 return res;
73 // Again some OS specifics stuff
74 #ifdef NL_OS_WINDOWS
75 const string nlLibPrefix; // empty
76 const string nlLibExt(".dll");
77 #elif defined(NL_OS_MAC)
78 const string nlLibPrefix("lib");
79 const string nlLibExt(".dylib");
80 #elif defined(NL_OS_UNIX)
81 const string nlLibPrefix("lib");
82 const string nlLibExt(".so");
83 #else
84 # error "You must define the default dynamic lib extention"
85 #endif
87 std::vector<std::string> CLibrary::_LibPaths;
90 CLibrary::CLibrary (const CLibrary &/* other */)
92 // Nothing to do has it is forbidden.
93 // Allowing copy require to manage reference count from CLibrary to the module resource.
94 nlassert(false);
97 CLibrary &CLibrary::operator =(const CLibrary &/* other */)
99 // Nothing to do has it is forbidden.
100 // Allowing assignment require to manage reference count from CLibrary to the module resource.
101 nlassert(false);
102 return *this;
105 std::string CLibrary::makeLibName(const std::string &baseName)
107 return nlLibPrefix+baseName+nlLibSuffix+nlLibExt;
110 std::string CLibrary::cleanLibName(const std::string &decoratedName)
112 // remove path and extension
113 string ret = CFile::getFilenameWithoutExtension(decoratedName);
115 if (!nlLibPrefix.empty())
117 // remove prefix
118 if (ret.find(nlLibPrefix) == 0)
119 ret = ret.substr(nlLibPrefix.size());
121 if (!nlLibSuffix.empty())
123 // remove suffix
124 if (ret.substr(ret.size()-nlLibSuffix.size()) == nlLibSuffix)
125 ret = ret.substr(0, ret.size() - nlLibSuffix.size());
128 return ret;
131 void CLibrary::addLibPaths(const std::vector<std::string> &paths)
133 for (uint i=0; i<paths.size(); ++i)
135 string newPath = CPath::standardizePath(paths[i]);
137 // only add new path
138 if (std::find(_LibPaths.begin(), _LibPaths.end(), newPath) == _LibPaths.end())
140 _LibPaths.push_back(newPath);
145 void CLibrary::addLibPath(const std::string &path)
147 string newPath = CPath::standardizePath(path);
149 // only add new path
150 if (std::find(_LibPaths.begin(), _LibPaths.end(), newPath) == _LibPaths.end())
152 _LibPaths.push_back(newPath);
156 CLibrary::CLibrary()
157 : _LibHandle(NULL),
158 _Ownership(true),
159 _PureNelLibrary(NULL)
163 CLibrary::CLibrary(NL_LIB_HANDLE libHandle, bool ownership)
164 : _PureNelLibrary(NULL)
166 _LibHandle = libHandle;
167 _Ownership = ownership;
168 _LibFileName = "unknown";
171 CLibrary::CLibrary(const std::string &libName, bool addNelDecoration, bool tryLibPath, bool ownership)
172 : _PureNelLibrary(NULL)
174 loadLibrary(libName, addNelDecoration, tryLibPath, ownership);
175 // Assert here !
176 nlassert(_LibHandle != NULL);
180 CLibrary::~CLibrary()
182 if (_LibHandle != NULL && _Ownership)
184 nlFreeLibrary(_LibHandle);
188 bool CLibrary::loadLibrary(const std::string &libName, bool addNelDecoration, bool tryLibPath, bool ownership)
190 _Ownership = ownership;
191 string libPath = libName;
193 if (addNelDecoration)
194 libPath = makeLibName(libPath);
196 if (tryLibPath)
198 // remove any directory spec
199 string filename = CFile::getFilename(libPath);
201 for (uint i=0; i<_LibPaths.size(); ++i)
203 string pathname = _LibPaths[i]+filename;
204 if (CFile::isExists(pathname))
206 // we found it, replace libPath
207 libPath = pathname;
208 break;
213 nldebug("Loading dynamic library '%s'", libPath.c_str());
214 // load the lib now
215 _LibHandle = nlLoadLibrary(libPath);
216 _LibFileName = libPath;
217 // MTR: some new error handling. Just logs if it couldn't load the handle.
218 if(_LibHandle == NULL)
220 #ifdef NL_OS_UNIX
221 const char *errormsg = dlerror();
222 #else
223 const char *errormsg = "Verify DLL existence";
224 #endif
225 nlwarning("Loading library %s failed: %s", libPath.c_str(), errormsg);
227 else
229 // check for 'pure' NeL library
230 void *entryPoint = getSymbolAddress(NL_MACRO_TO_STR(NLMISC_PURE_LIB_ENTRY_POINT));
231 if (entryPoint != NULL)
233 // rebuild the interface pointer
234 _PureNelLibrary = *(reinterpret_cast<INelLibrary**>(entryPoint));
235 // call the private initialization method.
236 _PureNelLibrary->_onLibraryLoaded(INelContext::getInstance());
240 return _LibHandle != NULL;
243 void CLibrary::freeLibrary()
245 if (_LibHandle)
247 nlassert(_Ownership);
249 if (_PureNelLibrary)
251 // call the private finalization method.
252 _PureNelLibrary->_onLibraryUnloaded();
255 nldebug("Freeing dynamic library '%s'", _LibFileName.c_str());
256 nlFreeLibrary(_LibHandle);
258 _PureNelLibrary = NULL;
259 _LibHandle = NULL;
260 _Ownership = false;
261 _LibFileName.clear();
265 void *CLibrary::getSymbolAddress(const std::string &symbolName)
267 nlassert(_LibHandle != NULL);
269 return nlGetSymbolAddress(_LibHandle, symbolName);
272 bool CLibrary::isLibraryLoaded()
274 return _LibHandle != NULL;
277 bool CLibrary::isLibraryPure()
279 return _LibHandle != NULL && _PureNelLibrary != NULL;
282 INelLibrary *CLibrary::getNelLibraryInterface()
284 if (!isLibraryPure())
285 return NULL;
287 return _PureNelLibrary;
290 INelLibrary::~INelLibrary()
292 // cleanup ram
293 if (_LibContext != NULL)
294 delete _LibContext;
297 void INelLibrary::_onLibraryLoaded(INelContext &nelContext)
299 ++_LoadingCounter;
301 if (_LoadingCounter == 1)
303 // Linux relocates all symbols, so this is unnecessary.
304 #ifdef NL_OS_WINDOWS
305 // initialize NeL context
306 nlassert(!NLMISC::INelContext::isContextInitialised());
307 #endif // NL_OS_WINDOWS
309 _LibContext = new CLibraryContext(nelContext);
311 else
313 nlassert(NLMISC::INelContext::isContextInitialised());
316 onLibraryLoaded(_LoadingCounter==1);
319 void INelLibrary::_onLibraryUnloaded()
321 nlassert(_LoadingCounter > 0);
323 onLibraryUnloaded(_LoadingCounter == 1);
325 --_LoadingCounter;
328 uint32 INelLibrary::getLoadingCounter()
330 return _LoadingCounter;
334 } // namespace NLMISC