Loading...
Searching...
No Matches
DynLib.h
Go to the documentation of this file.
1/*
2** This file is part of eOn.
3**
4** SPDX-License-Identifier: BSD-3-Clause
5**
6** Copyright (c) 2010--present, eOn Development Team
7** All rights reserved.
8**
9** Repo:
10** https://github.com/TheochemUI/eOn
11*/
12#pragma once
13
16
17#include <string>
18
19#ifdef _WIN32
20#ifndef WIN32_LEAN_AND_MEAN
21#define WIN32_LEAN_AND_MEAN
22#endif
23#include <windows.h>
24#else
25#include <dlfcn.h>
26#endif
27
28namespace eonc::dynlib {
29
30#ifdef _WIN32
31using Handle = HMODULE;
32
33inline Handle open(const char *name) noexcept { return LoadLibraryA(name); }
34
35inline void *sym(Handle h, const char *name) noexcept {
36 return reinterpret_cast<void *>(GetProcAddress(h, name));
37}
38
39inline void close(Handle h) noexcept {
40 if (h)
41 FreeLibrary(h);
42}
43
44inline std::string error() {
45 DWORD err = GetLastError();
46 if (err == 0)
47 return {};
48 LPSTR buf = nullptr;
49 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
50 FORMAT_MESSAGE_IGNORE_INSERTS,
51 nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
52 reinterpret_cast<LPSTR>(&buf), 0, nullptr);
53 std::string msg(buf ? buf : "unknown error");
54 if (buf)
55 LocalFree(buf);
56 return msg;
57}
58
59#else // POSIX (Linux, macOS)
60using Handle = void *;
61
62inline Handle open(const char *name) noexcept {
63 // RTLD_DEEPBIND (Linux-only): make the library prefer its own symbols over
64 // globally-visible ones. Without this, Fortran helper symbols exported by
65 // Fortran shared libraries (e.g. neighbours_ in libeon_sw.so) can be
66 // hijacked by identically-named symbols in other loaded libraries (e.g.
67 // libxtb.so.6 also exports neighbours_), causing mis-dispatch and SIGSEGV.
68#if defined(__linux__)
69 return dlopen(name, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
70#else
71 return dlopen(name, RTLD_NOW | RTLD_LOCAL);
72#endif
73}
74
75inline void *sym(Handle h, const char *name) noexcept { return dlsym(h, name); }
76
77inline void close(Handle h) noexcept {
78 if (h)
79 dlclose(h);
80}
81
82inline std::string error() {
83 const char *msg = dlerror();
84 return msg ? std::string(msg) : std::string{};
85}
86#endif
87
89inline Handle openFirst(const char *const names[]) noexcept {
90 for (const char *const *name = names; *name; ++name) {
91 Handle h = open(*name);
92 if (h)
93 return h;
94 }
95 return {};
96}
97
99template <typename Fn> Fn loadSym(Handle h, const char *name) noexcept {
100 return reinterpret_cast<Fn>(sym(h, name));
101}
102
103} // namespace eonc::dynlib
Cross-platform dynamic library loading abstraction.
Definition DynLib.h:28
void * sym(Handle h, const char *name) noexcept
Definition DynLib.h:75
void * Handle
Definition DynLib.h:60
std::string error()
Definition DynLib.h:82
Handle open(const char *name) noexcept
Definition DynLib.h:62
void close(Handle h) noexcept
Definition DynLib.h:77
Fn loadSym(Handle h, const char *name) noexcept
Load a symbol and cast to a function pointer type.
Definition DynLib.h:99
Handle openFirst(const char *const names[]) noexcept
Try a list of library names in order, return first successful handle.
Definition DynLib.h:89