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
28#define ERR_DLNOTFOUND 1001
29#define ERR_FACTORYNOTFOUND 1002
30#define ERR_DLHANDLENOTFOUND 1003
31
32
54{
55private:
57 std::string dlFileName;
58
64 bool doesFileExists(const std::string& name) {
65 struct stat buffer{};
66 return (stat(name.c_str(), &buffer) == 0);
67 }
68
70 std::shared_ptr<GLogger> log;
71
72public:
74 DynamicLib() = default;
75
85 DynamicLib(std::shared_ptr<GLogger> logger, std::string path) : dlFileName(path), log(logger), handle(nullptr) {
86 log->debug(CONSTRUCTOR, "Instantiating ", path);
87 log->debug(NORMAL, "Trying ", dlFileName);
88
89 // Try GEMC_PLUGIN_PATH directories before falling back to gemc installation paths.
90 if (!doesFileExists(dlFileName)) {
91 log->debug(NORMAL, dlFileName, " not found...");
92
93 if (const char* envPath = std::getenv("GEMC_PLUGIN_PATH")) {
94 std::istringstream ss(envPath);
95 std::string dir;
96 while (std::getline(ss, dir, ':')) {
97 const std::string candidate = dir + "/" + path;
98 if (doesFileExists(candidate)) {
99 dlFileName = candidate;
100 break;
101 }
102 }
103 }
104 log->debug(NORMAL, "Trying ", dlFileName);
105 }
106
107 // Try installation path + "/lib" if not found at the provided location.
108 if (!doesFileExists(dlFileName)) {
109 log->debug(NORMAL, dlFileName, " not found...");
110
111 std::filesystem::path gemcRoot = gutilities::gemc_root();
112 dlFileName = gemcRoot.string() + "/lib/" + path;
113
114 log->debug(NORMAL, "Trying ", dlFileName);
115 }
116
117 // Try installation path + "/build" if not found - allows Meson tests to run from the build dir.
118 if (!doesFileExists(dlFileName)) {
119 log->debug(NORMAL, dlFileName, " not found...");
120
121 std::filesystem::path gemcRoot = gutilities::gemc_root();
122 dlFileName = gemcRoot.string() + "/build/" + path;
123
124 log->debug(NORMAL, "Trying ", dlFileName);
125 }
126
127 if (doesFileExists(dlFileName)) {
128 dlFileName = std::filesystem::absolute(dlFileName).string();
129 handle = load_lib(dlFileName);
130 if (handle == nullptr) {
131 char const* const dlopen_error = dlerror();
132 log->error(ERR_DLHANDLENOTFOUND, "File ", dlFileName, " found, but handle is null. dlopen_error >> ",
133 dlopen_error != nullptr ? dlopen_error : "unknown dlopen error");
134 }
135 else { log->info(1, "Loaded ", dlFileName); }
136 }
137 else {
138 const char* envPath = std::getenv("GEMC_PLUGIN_PATH");
139 log->error(ERR_DLNOTFOUND,
140 "could not find ", dlFileName, "\n",
141 " GEMC_PLUGIN_PATH = ", (envPath ? envPath : "(not set)"), "\n",
142 " Hint: set GEMC_PLUGIN_PATH or use -plugin_path=<dir> to the directory ",
143 "containing *.gplugin files.");
144 }
145 }
146
152 dlhandle handle = nullptr;
153
160 if (handle != nullptr) {
161 close_lib(handle);
162 log->debug(DESTRUCTOR, "Destroying ", dlFileName);
163 }
164 }
165};
166
167
179dlhandle load_lib(const std::string& lib) // never throws
180{
181 dlhandle h = nullptr;
182
183#if defined(__linux__) && defined(RTLD_NODELETE)
184 constexpr int dlopen_flags = RTLD_NOW | RTLD_NODELETE;
185#else
186 constexpr int dlopen_flags = RTLD_NOW;
187#endif
188
189 // If the caller already supplied a path (has a slash) just try it.
190 if (lib.find('/') != std::string::npos) { h = dlopen(lib.c_str(), dlopen_flags); }
191 else {
192 // 1. Try the file in the current working directory.
193 std::string cwdPath = "./" + lib;
194 h = dlopen(cwdPath.c_str(), dlopen_flags);
195
196 // 2. Fallback to the normal search path so LD_LIBRARY_PATH,
197 // RPATH/RUNPATH, system dirs, etc. are still honoured.
198 if (!h) { h = dlopen(lib.c_str(), dlopen_flags); }
199 }
200 return h; // may be nullptr – caller should check and use dlerror()
201}
202
207static void close_lib(dlhandle handle) { dlclose(handle); }
#define ERR_DLNOTFOUND
Definition gdl.h:28
#define ERR_DLHANDLENOTFOUND
Definition gdl.h:30
void * dlhandle
Opaque handle returned by dlopen and consumed by dlsym / dlclose.
Definition gdl.h:22
CONSTRUCTOR
NORMAL
DESTRUCTOR
std::filesystem::path gemc_root()
Helper that loads a shared library and holds its POSIX handle.
Definition gdl.h:54
DynamicLib(std::shared_ptr< GLogger > logger, std::string path)
Construct and attempt to load a dynamic library.
Definition gdl.h:85
dlhandle handle
POSIX handle of the dynamic library.
Definition gdl.h:152
~DynamicLib()
Destructor closes the library handle (if loaded).
Definition gdl.h:159
DynamicLib()=default
Default constructor (does not load anything).