129 lines
3.2 KiB
C++
129 lines
3.2 KiB
C++
#include "plugin_loader.h"
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#else
|
|
#include <dlfcn.h>
|
|
#endif
|
|
|
|
namespace rk3588 {
|
|
|
|
namespace {
|
|
|
|
void* LoadLibraryHandle(const std::string& path, std::string& err) {
|
|
#ifdef _WIN32
|
|
HMODULE handle = LoadLibraryA(path.c_str());
|
|
if (!handle) {
|
|
err = "LoadLibrary failed for " + path;
|
|
}
|
|
return handle;
|
|
#else
|
|
void* handle = dlopen(path.c_str(), RTLD_LAZY);
|
|
if (!handle) {
|
|
const char* dl_err = dlerror();
|
|
err = dl_err ? dl_err : "dlopen failed";
|
|
}
|
|
return handle;
|
|
#endif
|
|
}
|
|
|
|
void CloseLibraryHandle(void* handle) {
|
|
if (!handle) return;
|
|
#ifdef _WIN32
|
|
FreeLibrary(static_cast<HMODULE>(handle));
|
|
#else
|
|
dlclose(handle);
|
|
#endif
|
|
}
|
|
|
|
void* LoadSymbol(void* handle, const char* name) {
|
|
#ifdef _WIN32
|
|
return reinterpret_cast<void*>(GetProcAddress(static_cast<HMODULE>(handle), name));
|
|
#else
|
|
return dlsym(handle, name);
|
|
#endif
|
|
}
|
|
|
|
std::string SharedLibExtension() {
|
|
#ifdef _WIN32
|
|
return ".dll";
|
|
#elif __APPLE__
|
|
return ".dylib";
|
|
#else
|
|
return ".so";
|
|
#endif
|
|
}
|
|
|
|
} // namespace
|
|
|
|
PluginLoader::PluginLoader(std::string plugin_dir)
|
|
: plugin_dir_(std::move(plugin_dir)) {}
|
|
|
|
PluginLoader::~PluginLoader() {
|
|
for (auto& kv : cache_) {
|
|
CloseLibraryHandle(kv.second.handle);
|
|
}
|
|
}
|
|
|
|
std::string PluginLoader::BuildLibraryPath(const std::string& type) const {
|
|
#ifdef _WIN32
|
|
return plugin_dir_ + "/" + type + SharedLibExtension();
|
|
#else
|
|
return plugin_dir_ + "/lib" + type + SharedLibExtension();
|
|
#endif
|
|
}
|
|
|
|
bool PluginLoader::LoadPlugin(const std::string& type, PluginHandle& out, std::string& err) {
|
|
std::string path = BuildLibraryPath(type);
|
|
void* handle = LoadLibraryHandle(path, err);
|
|
if (!handle) return false;
|
|
|
|
auto create = reinterpret_cast<CreateNodeFn>(LoadSymbol(handle, "CreateNode"));
|
|
auto get_type = reinterpret_cast<GetTypeFn>(LoadSymbol(handle, "GetNodeType"));
|
|
auto get_abi = reinterpret_cast<GetAbiFn>(LoadSymbol(handle, "GetAbiVersion"));
|
|
if (!create || !get_type || !get_abi) {
|
|
err = "Missing required symbols in plugin: " + path;
|
|
CloseLibraryHandle(handle);
|
|
return false;
|
|
}
|
|
if (get_abi() != kNodeAbiVersion) {
|
|
std::ostringstream oss;
|
|
oss << "ABI mismatch for plugin " << type << ": expected " << kNodeAbiVersion
|
|
<< " got " << get_abi();
|
|
err = oss.str();
|
|
CloseLibraryHandle(handle);
|
|
return false;
|
|
}
|
|
out.handle = handle;
|
|
out.create = create;
|
|
out.get_type = get_type;
|
|
out.get_abi = get_abi;
|
|
return true;
|
|
}
|
|
|
|
std::unique_ptr<INode> PluginLoader::Create(const std::string& type, std::string& err) {
|
|
auto it = cache_.find(type);
|
|
if (it == cache_.end()) {
|
|
PluginHandle handle;
|
|
if (!LoadPlugin(type, handle, err)) {
|
|
std::cerr << "[PluginLoader] Failed to load plugin '" << type << "': " << err
|
|
<< "\n";
|
|
return nullptr;
|
|
}
|
|
it = cache_.emplace(type, std::move(handle)).first;
|
|
}
|
|
|
|
PluginHandle& handle = it->second;
|
|
std::unique_ptr<INode> node(handle.create());
|
|
if (!node) {
|
|
err = "CreateNode returned null for type " + type;
|
|
return nullptr;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
} // namespace rk3588
|