Loading [MathJax]/extensions/tex2jax.js
mbxmlutils  1.3.0
Multi-Body XML Utils
All Classes Functions Typedefs Enumerations
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# ifndef WIN32_LEAN_AND_MEAN
39# define WIN32_LEAN_AND_MEAN
40# endif
41# include <windows.h>
42#else
43# include <dlfcn.h>
44#endif
45
46namespace {
47
48inline std::string getLastError() {
49#ifndef _WIN32
50 const char *err=dlerror();
51 return err?err:"";
52#else
53 return std::to_string(GetLastError());
54#endif
55}
56
57}
58
59namespace MBXMLUtils::SharedLibrary {
60
61#ifndef _WIN32
62 using Handle = void *;
63#else
64 using Handle = HMODULE;
65#endif
66
67 using InitFuncType = int (*)();
68
69 template<typename T>
70 inline T getSymbol(const std::string &file, const std::string &symbolName, bool throwOnError=true);
71
72// Load the libary file, if not already loaded.
73// Unloads the library only at program exit!!!
74// file should be a canonical path.
75inline Handle load(const std::string &file, bool global=false) {
76 static std::map<std::string, Handle> library;
77 std::pair<std::map<std::string, Handle>::iterator, bool> res=library.insert(std::pair<std::string, Handle>(file, NULL));
78 if(res.second) {
79#ifndef _WIN32
80 res.first->second=dlopen(file.c_str(), RTLD_NOW | (global ? RTLD_GLOBAL : RTLD_LOCAL) | RTLD_DEEPBIND | RTLD_NODELETE);
81#else
82 std::string fileWinSep=file;
83 std::replace(fileWinSep.begin(), fileWinSep.end(), '/', '\\'); // LoadLibraryEx can not handle '/' as path separator
84 res.first->second=LoadLibraryEx(fileWinSep.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
85#endif
86 if(!res.first->second)
87 throw std::runtime_error("Unable to load the library '"+file+"': "+getLastError());
88
89 // call the init function if it exists
90 auto initFunc=getSymbol<InitFuncType>(file, "MBXMLUtils_SharedLibrary_init", false);
91 if(initFunc) {
92 int ret=initFunc();
93 if(ret)
94 throw std::runtime_error("Unable to initialize the library '"+file+"'.\n"
95 "The function 'MBXMLUtils_SharedLibrary_init' returned with error code "+std::to_string(ret)+".");
96 }
97 }
98 return res.first->second;
99}
100
101// Load the libary file, if not already loaded and return the symbol symbolName.
102// Unloads the library only at program exit!!!
103template<typename T>
104inline T getSymbol(const std::string &file, const std::string &symbolName, bool throwOnError) {
105 Handle h=load(file);
106#ifndef _WIN32
107 void *addr=dlsym(h, symbolName.c_str());
108#else
109 void *addr=reinterpret_cast<void*>(GetProcAddress(h, symbolName.c_str()));
110#endif
111 if(!addr) {
112 if(throwOnError)
113 throw std::runtime_error("Unable to load the symbol '"+symbolName+"' from library '"+
114 file+"': "+getLastError());
115 else
116 return nullptr;
117 }
118 return reinterpret_cast<T>(reinterpret_cast<size_t>(addr));
119}
120
121}
122
123#endif