mbxmlutils 1.3.0 Multi-Body XML Utils

shared_library.h
1 /*
2 * Author: Markus Friedrich
3 *
4 * This file is free and unencumbered software released into the public domain.
5 *
6 * Anyone is free to copy, modify, publish, use, compile, sell, or
7 * distribute this software, either in source code form or as a compiled
8 * binary, for any purpose, commercial or non-commercial, and by any
9 * means.
10 *
11 * In jurisdictions that recognize copyright laws, the author or authors
12 * of this software dedicate any and all copyright interest in the
13 * software to the public domain. We make this dedication for the benefit
14 * of the public at large and to the detriment of our heirs and
15 * successors. We intend this dedication to be an overt act of
16 * relinquishment in perpetuity of all present and future rights to this
17 * software under copyright law.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * For more information, please refer to <http://unlicense.org/>
28 */
29
30 #ifndef _MBXMLUTILS_SHAREDLIBRARY_H_
31 #define _MBXMLUTILS_SHAREDLIBRARY_H_
32
33 #include <string>
34 #include <map>
35 #include <stdexcept>
36 #include <algorithm>
37 #ifdef _WIN32
38 # define WIN32_LEAN_AND_MEAN
39 # include <windows.h>
40 #else
41 # include <dlfcn.h>
42 #endif
43
44 namespace {
45
46 inline std::string getLastError() {
47 #ifndef _WIN32
48 const char *err=dlerror();
49 return err?err:"";
50 #else
51 return std::to_string(GetLastError());
52 #endif
53 }
54
55 }
56
57 namespace MBXMLUtils::SharedLibrary {
58
59 #ifndef _WIN32
60 using Handle = void *;
61 #else
62 using Handle = HMODULE;
63 #endif
64
65 using InitFuncType = int (*)();
66
67 template<typename T>
68 inline T getSymbol(const std::string &file, const std::string &symbolName, bool throwOnError=true);
69
70 // Load the libary file, if not already loaded.
71 // Unloads the library only at program exit!!!
72 // file should be a canonical path.
73 inline Handle load(const std::string &file, bool global=false) {
74 static std::map<std::string, Handle> library;
75 std::pair<std::map<std::string, Handle>::iterator, bool> res=library.insert(std::pair<std::string, Handle>(file, NULL));
76 if(res.second) {
77 #ifndef _WIN32
78 res.first->second=dlopen(file.c_str(), RTLD_NOW | (global ? RTLD_GLOBAL : RTLD_LOCAL) | RTLD_DEEPBIND | RTLD_NODELETE);
79 #else
80 std::string fileWinSep=file;
81 std::replace(fileWinSep.begin(), fileWinSep.end(), '/', '\\'); // LoadLibraryEx can not handle '/' as path separator
82 res.first->second=LoadLibraryEx(fileWinSep.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
83 #endif
84 if(!res.first->second)
85 throw std::runtime_error("Unable to load the library '"+file+"': "+getLastError());
86
87 // call the init function if it exists
88 auto initFunc=getSymbol<InitFuncType>(file, "MBXMLUtils_SharedLibrary_init", false);
89 if(initFunc) {
90 int ret=initFunc();
91 if(ret)
92 throw std::runtime_error("Unable to initialize the library '"+file+"'.\n"
93 "The function 'MBXMLUtils_SharedLibrary_init' returned with error code "+std::to_string(ret)+".");
94 }
95 }
96 return res.first->second;
97 }
98
99 // Load the libary file, if not already loaded and return the symbol symbolName.
100 // Unloads the library only at program exit!!!
101 template<typename T>
102 inline T getSymbol(const std::string &file, const std::string &symbolName, bool throwOnError) {
103 Handle h=load(file);
104 #ifndef _WIN32
105 void *addr=dlsym(h, symbolName.c_str());
106 #else
107 void *addr=reinterpret_cast<void*>(GetProcAddress(h, symbolName.c_str()));
108 #endif
109 if(!addr) {
110 if(throwOnError)
111 throw std::runtime_error("Unable to load the symbol '"+symbolName+"' from library '"+
112 file+"': "+getLastError());
113 else
114 return nullptr;
115 }
116 return reinterpret_cast<T>(reinterpret_cast<size_t>(addr));
117 }
118
119 }
120
121 #endif