14#include <unordered_map>
18#define PLUGINS_EXTENSION ".dll"
22#define PLUGINS_EXTENSION ".dylib"
24#define PLUGINS_EXTENSION ".so"
58 other.handle =
nullptr;
75 explicit operator bool()
const {
return handle !=
nullptr; }
102 template <std::derived_from<IPlugin> T> std::shared_ptr<T>
loadPlugin(
const std::string &path)
104 std::scoped_lock lock(
m_mutex);
107 throw std::runtime_error(
"Plugin already loaded: " + path);
112 std::unique_ptr<IPlugin> plugin(entry());
114 throw std::runtime_error(
"EntryPoint failed: " + path);
116 T *typed =
dynamic_cast<T *
>(plugin.get());
118 throw std::runtime_error(
"Plugin type mismatch: " + path);
120 auto [it, inserted] =
m_plugins.emplace(path, std::move(plugin));
122 throw std::runtime_error(
"Failed to store plugin: " + path);
128 std::shared_ptr<IPlugin> baseShared(it->second.get(), [](
IPlugin *) {});
129 return std::shared_ptr<T>(baseShared, typed);
135 std::unordered_map<std::string, std::unique_ptr<IPlugin>>
m_plugins;
141 const LibHandle handle = LoadLibraryA(path.c_str());
144 const DWORD errorCode = GetLastError();
146 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
147 FORMAT_MESSAGE_IGNORE_INSERTS,
148 nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
149 reinterpret_cast<LPSTR
>(&errorMsg), 0,
nullptr);
151 std::cerr <<
"[ERROR] Failed to load plugin: " << path <<
"\n[WinError " << errorCode <<
"] "
152 << (errorMsg ?
static_cast<LPSTR
>(errorMsg) :
"Unknown error") << std::endl;
157 throw std::runtime_error(
"Cannot load library: " + path);
161 const LibHandle handle = dlopen(path.c_str(), RTLD_LAZY);
164 const char *error = dlerror();
165 std::string msg =
"Cannot load library: " + path;
168 msg +=
" (" + std::string(error) +
")";
170 throw std::runtime_error(msg);
185 throw std::runtime_error(
"EntryPoint not found in plugin: " + path);
This file contains the plugin interface.
This file contains the Logger class.
static void log(const std::string &message, const LogLevel &logLevel)
Modern, type-safe plugin loader.
std::unordered_map< std::string, std::unique_ptr< IPlugin > > m_plugins
PluginLoader(PluginLoader &&)=delete
PluginLoader & operator=(PluginLoader &&)=delete
PluginLoader & operator=(const PluginLoader &)=delete
PluginLoader(const PluginLoader &)=delete
SharedLib loadLibrary(const std::string &path)
std::unordered_map< std::string, SharedLib > m_handles
EntryPointFn getEntryPoint(SharedLib &lib, const std::string &path)
std::shared_ptr< T > loadPlugin(const std::string &path)
Load a plugin of type T.
IPlugin *(*)() EntryPointFn
Handle to a dynamic library with RAII.
SharedLib & operator=(const SharedLib &)=delete
SharedLib(const LibHandle h=nullptr)
SharedLib & operator=(SharedLib &&other) noexcept
SharedLib(const SharedLib &)=delete
SharedLib(SharedLib &&other) noexcept