Loading...
Searching...
No Matches
eonc::PluginLoader Class Reference

#include <PluginLoader.h>

Public Member Functions

void add_config_paths (const std::string &colon_paths)
 Inject search paths from the eOn config file.
template<typename Fn>
Fn load_sym (const char *lib_base, const char *sym_name)
 Load a symbol from a named potential library.
void throw_not_found (const char *lib_base, const char *description) const
 Throw a descriptive error for a missing potential library.
bool lib_present (const char *lib_base) const
 Filesystem probe: a matching library file is on the configured search path.
const std::vector< std::string > & search_paths () const noexcept
 Get the current search paths (for diagnostics).
 PluginLoader (const PluginLoader &)=delete
PluginLoaderoperator= (const PluginLoader &)=delete

Static Public Member Functions

static PluginLoaderinstance ()
 Thread-safe singleton accessor (Meyer's pattern).

Private Member Functions

 PluginLoader ()
 ~PluginLoader ()
dynlib::Handle open_lib (const char *lib_base)
std::vector< std::string > lib_names (const char *lib_base) const
void append_paths (const std::string &path_str, char sep)

Private Attributes

std::vector< std::string > m_search_paths
std::mutex m_mutex
std::unordered_map< std::string, dynlib::Handlem_handles
std::string m_last_load_error
 Last dynlib::error() from a failed open (for throw_not_found).
bool m_last_load_saw_file = false

Detailed Description

Definition at line 41 of file PluginLoader.h.

Constructor & Destructor Documentation

◆ PluginLoader() [1/2]

eonc::PluginLoader::PluginLoader ( const PluginLoader & )
delete

◆ PluginLoader() [2/2]

eonc::PluginLoader::PluginLoader ( )
private

Definition at line 25 of file PluginLoader.cpp.

25 {
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}
void append_paths(const std::string &path_str, char sep)

◆ ~PluginLoader()

eonc::PluginLoader::~PluginLoader ( )
private

Definition at line 38 of file PluginLoader.cpp.

38 {
39 for (auto &[name, handle] : m_handles) {
40 dynlib::close(handle);
41 }
42}
std::unordered_map< std::string, dynlib::Handle > m_handles
void close(Handle h) noexcept
Definition DynLib.h:77

Member Function Documentation

◆ add_config_paths()

void eonc::PluginLoader::add_config_paths ( const std::string & colon_paths)

Inject search paths from the eOn config file.

Parameters
colon_pathscolon-separated directory list (may be empty) These paths are inserted before the EON_POTENTIALS_PATH paths.

Definition at line 66 of file PluginLoader.cpp.

66 {
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}
std::vector< std::string > m_search_paths

◆ append_paths()

void eonc::PluginLoader::append_paths ( const std::string & path_str,
char sep )
private

Definition at line 44 of file PluginLoader.cpp.

44 {
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}

◆ instance()

PluginLoader & eonc::PluginLoader::instance ( )
static

Thread-safe singleton accessor (Meyer's pattern).

Definition at line 20 of file PluginLoader.cpp.

20 {
21 static PluginLoader loader;
22 return loader;
23}
PluginLoader(const PluginLoader &)=delete

◆ lib_names()

std::vector< std::string > eonc::PluginLoader::lib_names ( const char * lib_base) const
private

Definition at line 100 of file PluginLoader.cpp.

100 {
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}

◆ lib_present()

bool eonc::PluginLoader::lib_present ( const char * lib_base) const
nodiscard

Filesystem probe: a matching library file is on the configured search path.

Does not dlopen, so plugin static initializers (banners) do not run.

Definition at line 164 of file PluginLoader.cpp.

164 {
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}
std::vector< std::string > lib_names(const char *lib_base) const

◆ load_sym()

template<typename Fn>
Fn eonc::PluginLoader::load_sym ( const char * lib_base,
const char * sym_name )
inline

Load a symbol from a named potential library.

Parameters
lib_baseBase name without platform prefix/suffix (e.g. "eon_sw")
sym_nameSymbol to load (e.g. "sw_")
Returns
Function pointer, or nullptr if not found.

Definition at line 56 of file PluginLoader.h.

56 {
57 dynlib::Handle h = open_lib(lib_base);
58 if (!h)
59 return nullptr;
60 return dynlib::loadSym<Fn>(h, sym_name);
61 }
dynlib::Handle open_lib(const char *lib_base)
void * Handle
Definition DynLib.h:60
Fn loadSym(Handle h, const char *name) noexcept
Load a symbol and cast to a function pointer type.
Definition DynLib.h:99

◆ open_lib()

dynlib::Handle eonc::PluginLoader::open_lib ( const char * lib_base)
private

Definition at line 113 of file PluginLoader.cpp.

113 {
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}
std::string m_last_load_error
Last dynlib::error() from a failed open (for throw_not_found).
std::string error()
Definition DynLib.h:82
Handle open(const char *name) noexcept
Definition DynLib.h:62

◆ operator=()

PluginLoader & eonc::PluginLoader::operator= ( const PluginLoader & )
delete

◆ search_paths()

const std::vector< std::string > & eonc::PluginLoader::search_paths ( ) const
inlinenodiscardnoexcept

Get the current search paths (for diagnostics).

Definition at line 73 of file PluginLoader.h.

73 {
74 return m_search_paths;
75 }

◆ throw_not_found()

void eonc::PluginLoader::throw_not_found ( const char * lib_base,
const char * description ) const

Throw a descriptive error for a missing potential library.

Definition at line 177 of file PluginLoader.cpp.

178 {
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 }
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}

Member Data Documentation

◆ m_handles

std::unordered_map<std::string, dynlib::Handle> eonc::PluginLoader::m_handles
private

Definition at line 90 of file PluginLoader.h.

◆ m_last_load_error

std::string eonc::PluginLoader::m_last_load_error
private

Last dynlib::error() from a failed open (for throw_not_found).

Definition at line 92 of file PluginLoader.h.

◆ m_last_load_saw_file

bool eonc::PluginLoader::m_last_load_saw_file = false
private

Definition at line 93 of file PluginLoader.h.

◆ m_mutex

std::mutex eonc::PluginLoader::m_mutex
mutableprivate

Definition at line 89 of file PluginLoader.h.

◆ m_search_paths

std::vector<std::string> eonc::PluginLoader::m_search_paths
private

Definition at line 88 of file PluginLoader.h.


The documentation for this class was generated from the following files: