1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
22 #include "nel/misc/dynloadlib.h"
23 #include "nel/misc/path.h"
34 NL_LIB_HANDLE
nlLoadLibrary(const std::string
&libName
)
36 NL_LIB_HANDLE res
= 0;
38 res
= LoadLibraryW(nlUtf8ToWide(libName
));
39 #elif defined(NL_OS_UNIX)
40 res
= dlopen(libName
.c_str(), RTLD_NOW
);
42 # error "You must code nlLoadLibrary() for your platform"
44 if(res
== 0) nlwarning("Load library '%s' failed: %s", libName
.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
48 bool nlFreeLibrary(NL_LIB_HANDLE libHandle
)
51 return FreeLibrary(libHandle
) > 0;
52 #elif defined(NL_OS_UNIX)
53 return dlclose(libHandle
) == 0;
55 # error "You must code nlFreeLibrary() for your platform"
59 void *nlGetSymbolAddress(NL_LIB_HANDLE libHandle
, const std::string
&procName
)
63 res
= (void *)GetProcAddress(libHandle
, procName
.c_str());
64 #elif defined(NL_OS_UNIX)
65 res
= dlsym(libHandle
, procName
.c_str());
67 # error "You must code nlGetProcAddress() for your platform"
69 if(res
== 0) nlwarning("Getting symbol address of '%s' failed: %s", procName
.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
73 // Again some OS specifics stuff
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");
84 # error "You must define the default dynamic lib extention"
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.
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.
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())
118 if (ret
.find(nlLibPrefix
) == 0)
119 ret
= ret
.substr(nlLibPrefix
.size());
121 if (!nlLibSuffix
.empty())
124 if (ret
.substr(ret
.size()-nlLibSuffix
.size()) == nlLibSuffix
)
125 ret
= ret
.substr(0, ret
.size() - nlLibSuffix
.size());
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
]);
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
);
150 if (std::find(_LibPaths
.begin(), _LibPaths
.end(), newPath
) == _LibPaths
.end())
152 _LibPaths
.push_back(newPath
);
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
);
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
);
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
213 nldebug("Loading dynamic library '%s'", libPath
.c_str());
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
)
221 const char *errormsg
= dlerror();
223 const char *errormsg
= "Verify DLL existence";
225 nlwarning("Loading library %s failed: %s", libPath
.c_str(), errormsg
);
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()
247 nlassert(_Ownership
);
251 // call the private finalization method.
252 _PureNelLibrary
->_onLibraryUnloaded();
255 nldebug("Freeing dynamic library '%s'", _LibFileName
.c_str());
256 nlFreeLibrary(_LibHandle
);
258 _PureNelLibrary
= NULL
;
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())
287 return _PureNelLibrary
;
290 INelLibrary::~INelLibrary()
293 if (_LibContext
!= NULL
)
297 void INelLibrary::_onLibraryLoaded(INelContext
&nelContext
)
301 if (_LoadingCounter
== 1)
303 // Linux relocates all symbols, so this is unnecessary.
305 // initialize NeL context
306 nlassert(!NLMISC::INelContext::isContextInitialised());
307 #endif // NL_OS_WINDOWS
309 _LibContext
= new CLibraryContext(nelContext
);
313 nlassert(NLMISC::INelContext::isContextInitialised());
316 onLibraryLoaded(_LoadingCounter
==1);
319 void INelLibrary::_onLibraryUnloaded()
321 nlassert(_LoadingCounter
> 0);
323 onLibraryUnloaded(_LoadingCounter
== 1);
328 uint32
INelLibrary::getLoadingCounter()
330 return _LoadingCounter
;
334 } // namespace NLMISC