eOn client
Long-timescale dynamics: aKMC, NEB, parallel replica
☾
Toggle main menu visibility
Loading...
Searching...
No Matches
PluginLoader.cpp
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
#include "
eon/potentials/PluginLoader.h
"
13
14
#include <cstdlib>
15
#include <filesystem>
16
#include <sstream>
17
18
namespace
eonc
{
19
20
PluginLoader
&
PluginLoader::instance
() {
21
static
PluginLoader
loader;
22
return
loader;
23
}
24
25
PluginLoader::PluginLoader
() {
26
// Seed from EON_POTENTIALS_PATH env var (colon-separated on POSIX).
27
// Config-file paths are prepended later via add_config_paths().
28
const
char
*env = std::getenv(
"EON_POTENTIALS_PATH"
);
29
if
(env && *env) {
30
#ifdef _WIN32
31
append_paths
(env,
';'
);
32
#else
33
append_paths
(env,
':'
);
34
#endif
35
}
36
}
37
38
PluginLoader::~PluginLoader
() {
39
for
(
auto
&[name, handle] :
m_handles
) {
40
dynlib::close
(handle);
41
}
42
}
43
44
void
PluginLoader::append_paths
(
const
std::string &path_str,
char
sep) {
45
std::string::size_type start = 0;
46
while
(start < path_str.size()) {
47
auto
pos = path_str.find(sep, start);
48
if
(pos == std::string::npos)
49
pos = path_str.size();
50
if
(pos > start) {
51
std::string p = path_str.substr(start, pos - start);
52
bool
dup =
false
;
53
for
(
const
auto
&existing :
m_search_paths
) {
54
if
(existing == p) {
55
dup =
true
;
56
break
;
57
}
58
}
59
if
(!dup)
60
m_search_paths
.push_back(std::move(p));
61
}
62
start = pos + 1;
63
}
64
}
65
66
void
PluginLoader::add_config_paths
(
const
std::string &colon_paths) {
67
if
(colon_paths.empty())
68
return
;
69
std::lock_guard<std::mutex> lock(
m_mutex
);
70
// Config paths have higher priority than env-var paths: insert at front.
71
std::vector<std::string> new_paths;
72
#ifdef _WIN32
73
const
char
sep =
';'
;
74
#else
75
const
char
sep =
':'
;
76
#endif
77
std::string::size_type start = 0;
78
while
(start < colon_paths.size()) {
79
auto
pos = colon_paths.find(sep, start);
80
if
(pos == std::string::npos)
81
pos = colon_paths.size();
82
if
(pos > start) {
83
std::string p = colon_paths.substr(start, pos - start);
84
bool
dup =
false
;
85
for
(
const
auto
&existing :
m_search_paths
) {
86
if
(existing == p) {
87
dup =
true
;
88
break
;
89
}
90
}
91
if
(!dup)
92
new_paths.push_back(std::move(p));
93
}
94
start = pos + 1;
95
}
96
m_search_paths
.insert(
m_search_paths
.begin(), new_paths.begin(),
97
new_paths.end());
98
}
99
100
std::vector<std::string>
PluginLoader::lib_names
(
const
char
*lib_base)
const
{
101
std::vector<std::string> names;
102
#ifdef _WIN32
103
names.push_back(std::string(lib_base) +
".dll"
);
104
names.push_back(std::string(
"lib"
) + lib_base +
".dll"
);
105
#elif defined(__APPLE__)
106
names.push_back(std::string(
"lib"
) + lib_base +
".dylib"
);
107
#else
108
names.push_back(std::string(
"lib"
) + lib_base +
".so"
);
109
#endif
110
return
names;
111
}
112
113
dynlib::Handle
PluginLoader::open_lib
(
const
char
*lib_base) {
114
std::lock_guard<std::mutex> lock(
m_mutex
);
115
116
auto
it =
m_handles
.find(lib_base);
117
if
(it !=
m_handles
.end()) {
118
return
it->second;
119
}
120
121
auto
names =
lib_names
(lib_base);
122
dynlib::Handle
h{};
123
std::string last_err;
124
bool
any_file =
false
;
125
126
// Probe the filesystem first. dlopen of a present plugin runs that
127
// library's static initializers (Fortran / LAMMPS banners), so skip
128
// names that are not on disk.
129
for
(
const
auto
&dir :
m_search_paths
) {
130
for
(
const
auto
&name : names) {
131
std::string full = (std::filesystem::path(dir) / name).
string
();
132
std::error_code ec;
133
if
(!std::filesystem::exists(full, ec))
134
continue
;
135
any_file =
true
;
136
h =
dynlib::open
(full.c_str());
137
if
(h) {
138
m_handles
[lib_base] = h;
139
return
h;
140
}
141
// Capture immediately after LoadLibrary/dlopen (GetLastError/dlerror).
142
last_err =
dynlib::error
();
143
}
144
}
145
146
// Fall back to system search (LD_LIBRARY_PATH, etc.)
147
for
(
const
auto
&name : names) {
148
h =
dynlib::open
(name.c_str());
149
if
(h) {
150
m_handles
[lib_base] = h;
151
return
h;
152
}
153
last_err =
dynlib::error
();
154
}
155
156
// Stash diagnostics for throw_not_found (thread-local; open is
157
// mutex-guarded).
158
m_last_load_error
= last_err;
159
m_last_load_saw_file
= any_file;
160
m_handles
[lib_base] =
nullptr
;
161
return
nullptr
;
162
}
163
164
bool
PluginLoader::lib_present
(
const
char
*lib_base)
const
{
165
std::lock_guard<std::mutex> lock(
m_mutex
);
166
auto
names =
lib_names
(lib_base);
167
for
(
const
auto
&dir :
m_search_paths
) {
168
for
(
const
auto
&name : names) {
169
std::error_code ec;
170
if
(std::filesystem::exists(std::filesystem::path(dir) / name, ec))
171
return
true
;
172
}
173
}
174
return
false
;
175
}
176
177
void
PluginLoader::throw_not_found
(
const
char
*lib_base,
178
const
char
*description)
const
{
179
auto
names =
lib_names
(lib_base);
180
std::ostringstream oss;
181
oss << description <<
" requested but library not found.\n"
182
<<
"Looked for: "
;
183
for
(
size_t
i = 0; i < names.size(); ++i) {
184
if
(i > 0)
185
oss <<
", "
;
186
oss << names[i];
187
}
188
oss <<
"\n"
;
189
if
(!
m_search_paths
.empty()) {
190
oss <<
"Search paths (config potentials_path + EON_POTENTIALS_PATH):\n"
;
191
for
(
const
auto
&p :
m_search_paths
) {
192
oss <<
" "
<< p <<
"\n"
;
193
}
194
}
195
if
(
m_last_load_saw_file
) {
196
oss <<
"A matching file was present but LoadLibrary/dlopen failed"
;
197
if
(!
m_last_load_error
.empty())
198
oss <<
": "
<<
m_last_load_error
;
199
oss <<
"\n(often a missing flang_rt / FortranRuntime dependency on "
200
"PATH).\n"
;
201
}
else
if
(!
m_last_load_error
.empty()) {
202
oss <<
"Loader error: "
<<
m_last_load_error
<<
"\n"
;
203
}
204
oss <<
"Set [Potential] potentials_path in config.ini, "
205
"or set EON_POTENTIALS_PATH,\n"
206
"or ensure the libraries are in LD_LIBRARY_PATH."
;
207
throw
std::runtime_error(oss.str());
208
}
209
210
}
// namespace eonc
PluginLoader.h
eonc::PluginLoader::add_config_paths
void add_config_paths(const std::string &colon_paths)
Inject search paths from the eOn config file.
Definition
PluginLoader.cpp:66
eonc::PluginLoader::m_search_paths
std::vector< std::string > m_search_paths
Definition
PluginLoader.h:88
eonc::PluginLoader::m_last_load_saw_file
bool m_last_load_saw_file
Definition
PluginLoader.h:93
eonc::PluginLoader::lib_present
bool lib_present(const char *lib_base) const
Filesystem probe: a matching library file is on the configured search path.
Definition
PluginLoader.cpp:164
eonc::PluginLoader::PluginLoader
PluginLoader()
Definition
PluginLoader.cpp:25
eonc::PluginLoader::~PluginLoader
~PluginLoader()
Definition
PluginLoader.cpp:38
eonc::PluginLoader::instance
static PluginLoader & instance()
Thread-safe singleton accessor (Meyer's pattern).
Definition
PluginLoader.cpp:20
eonc::PluginLoader::append_paths
void append_paths(const std::string &path_str, char sep)
Definition
PluginLoader.cpp:44
eonc::PluginLoader::m_last_load_error
std::string m_last_load_error
Last dynlib::error() from a failed open (for throw_not_found).
Definition
PluginLoader.h:92
eonc::PluginLoader::PluginLoader
PluginLoader(const PluginLoader &)=delete
eonc::PluginLoader::lib_names
std::vector< std::string > lib_names(const char *lib_base) const
Definition
PluginLoader.cpp:100
eonc::PluginLoader::m_mutex
std::mutex m_mutex
Definition
PluginLoader.h:89
eonc::PluginLoader::open_lib
dynlib::Handle open_lib(const char *lib_base)
Definition
PluginLoader.cpp:113
eonc::PluginLoader::m_handles
std::unordered_map< std::string, dynlib::Handle > m_handles
Definition
PluginLoader.h:90
eonc::PluginLoader::throw_not_found
void throw_not_found(const char *lib_base, const char *description) const
Throw a descriptive error for a missing potential library.
Definition
PluginLoader.cpp:177
eonc::dynlib::Handle
void * Handle
Definition
DynLib.h:60
eonc::dynlib::error
std::string error()
Definition
DynLib.h:82
eonc::dynlib::open
Handle open(const char *name) noexcept
Definition
DynLib.h:62
eonc::dynlib::close
void close(Handle h) noexcept
Definition
DynLib.h:77
eonc
RAII resource manager for the ARTn C library with global synchronization.
Definition
ARTnSaddleSearch.cpp:19
client
potentials
PluginLoader.cpp
Generated by
1.17.0
Generated by
Doxygen 1.17.0
Analytics by
Antics
provided by
TurtleTech ehf