gfactory
Loading...
Searching...
No Matches
gdl.h
Go to the documentation of this file.
1#pragma once
2
3// geomc
4#include <gemc/glogging/glogger.h>
5#include <gemc/guts/gutilities.h>
6
7// POSIX dynamic loading
8// documentation: http://www.faqs.org/docs/Linux-mini/C++-dlopen.html
9#include <dlfcn.h>
10
11// c++
12#include <cstdlib>
13#include <filesystem>
14#include <sstream>
15#include <sys/stat.h> // to check if file exists
16#include <string>
17
22typedef void* dlhandle;
23
24static dlhandle load_lib(const std::string& path);
25static void close_lib(dlhandle handle);
26
27// exit codes: 1000s
28namespace gfactory {
29inline constexpr int ERR_DLNOTFOUND = 1001;
30inline constexpr int ERR_FACTORYNOTFOUND = 1002;
31inline constexpr int ERR_DLHANDLENOTFOUND = 1003;
32} // namespace gfactory
33
34
56{
57private:
59 std::string dlFileName;
60
66 bool doesFileExists(const std::string& name) {
67 struct stat buffer{};
68 return (stat(name.c_str(), &buffer) == 0);
69 }
70
72 std::shared_ptr<GLogger> log;
73
74public:
76 DynamicLib() = default;
77
87 DynamicLib(std::shared_ptr<GLogger> logger, std::string path) : dlFileName(path), log(logger), handle(nullptr) {
88 log->debug(CONSTRUCTOR, "Instantiating ", path);
89 log->debug(NORMAL, "Trying ", dlFileName);
90
91 // Try GEMC_PLUGIN_PATH directories before falling back to gemc installation paths.
92 if (!doesFileExists(dlFileName)) {
93 log->debug(NORMAL, dlFileName, " not found...");
94
95 if (const char* envPath = std::getenv("GEMC_PLUGIN_PATH")) {
96 std::istringstream ss(envPath);
97 std::string dir;
98 while (std::getline(ss, dir, ':')) {
99 const std::string candidate = dir + "/" + path;
100 if (doesFileExists(candidate)) {
101 dlFileName = candidate;
102 break;
103 }
104 }
105 }
106 log->debug(NORMAL, "Trying ", dlFileName);
107 }
108
109 // Try installation path + "/lib" if not found at the provided location.
110 if (!doesFileExists(dlFileName)) {
111 log->debug(NORMAL, dlFileName, " not found...");
112
113 std::filesystem::path gemcRoot = gutilities::gemc_root();
114 dlFileName = gemcRoot.string() + "/lib/" + path;
115
116 log->debug(NORMAL, "Trying ", dlFileName);
117 }
118
119 // Try installation path + "/build" if not found - allows Meson tests to run from the build dir.
120 if (!doesFileExists(dlFileName)) {
121 log->debug(NORMAL, dlFileName, " not found...");
122
123 std::filesystem::path gemcRoot = gutilities::gemc_root();
124 dlFileName = gemcRoot.string() + "/build/" + path;
125
126 log->debug(NORMAL, "Trying ", dlFileName);
127 }
128
129 if (doesFileExists(dlFileName)) {
130 dlFileName = std::filesystem::absolute(dlFileName).string();
131 handle = load_lib(dlFileName);
132 if (handle == nullptr) {
133 char const* const dlopen_error = dlerror();
134 log->error(gfactory::ERR_DLHANDLENOTFOUND, "File ", dlFileName,
135 " found, but handle is null. dlopen_error >> ",
136 dlopen_error != nullptr ? dlopen_error : "unknown dlopen error");
137 }
138 else { log->info(1, "Loaded ", dlFileName); }
139 }
140 else {
141 const char* envPath = std::getenv("GEMC_PLUGIN_PATH");
142 log->error(gfactory::ERR_DLNOTFOUND,
143 "could not find ", dlFileName, "\n",
144 " GEMC_PLUGIN_PATH = ", (envPath ? envPath : "(not set)"), "\n",
145 " Hint: set GEMC_PLUGIN_PATH or use -plugin_path=<dir> to the directory ",
146 "containing *.gplugin files.");
147 }
148 }
149
155 dlhandle handle = nullptr;
156
163 if (handle != nullptr) {
164 close_lib(handle);
165 log->debug(DESTRUCTOR, "Destroying ", dlFileName);
166 }
167 }
168};
169
170
182dlhandle load_lib(const std::string& lib) // never throws
183{
184 dlhandle h = nullptr;
185
186#if defined(__linux__) && defined(RTLD_NODELETE)
187 constexpr int dlopen_flags = RTLD_NOW | RTLD_NODELETE;
188#else
189 constexpr int dlopen_flags = RTLD_NOW;
190#endif
191
192 // If the caller already supplied a path (has a slash) just try it.
193 if (lib.find('/') != std::string::npos) { h = dlopen(lib.c_str(), dlopen_flags); }
194 else {
195 // 1. Try the file in the current working directory.
196 std::string cwdPath = "./" + lib;
197 h = dlopen(cwdPath.c_str(), dlopen_flags);
198
199 // 2. Fallback to the normal search path so LD_LIBRARY_PATH,
200 // RPATH/RUNPATH, system dirs, etc. are still honoured.
201 if (!h) { h = dlopen(lib.c_str(), dlopen_flags); }
202 }
203 return h; // may be nullptr – caller should check and use dlerror()
204}
205
210static void close_lib(dlhandle handle) { dlclose(handle); }
void * dlhandle
Opaque handle returned by dlopen and consumed by dlsym / dlclose.
Definition gdl.h:22
CONSTRUCTOR
NORMAL
DESTRUCTOR
Definition gdl.h:28
constexpr int ERR_FACTORYNOTFOUND
Definition gdl.h:30
constexpr int ERR_DLHANDLENOTFOUND
Definition gdl.h:31
constexpr int ERR_DLNOTFOUND
Definition gdl.h:29
std::filesystem::path gemc_root()
DynamicLib(std::shared_ptr< GLogger > logger, std::string path)
Construct and attempt to load a dynamic library.
Definition gdl.h:87
dlhandle handle
POSIX handle of the dynamic library.
Definition gdl.h:155
~DynamicLib()
Destructor closes the library handle (if loaded).
Definition gdl.h:162
DynamicLib()=default
Default constructor (does not load anything).