91 #include <string_view>
101 #define VLINK_PLUGIN_CREATE_FUNC_NAME vlink_plugin_create
107 #define VLINK_PLUGIN_DESTROY_FUNC_NAME vlink_plugin_destroy
185 [[nodiscard]] std::shared_ptr<T> load(
186 const std::string& lib_name, uint16_t
version_major, uint16_t version_minor,
const std::string& dir_name =
"",
187 const std::deque<std::string>& search_paths = default_search_path(),
202 bool unload(
const std::string& lib_name);
212 [[nodiscard]]
bool has_loaded(
const std::string& lib_name);
226 [[nodiscard]] std::string get_plugin_complex_id(
const std::string& lib_name);
254 uint16_t local_version_major, uint16_t local_version_minor,
255 const std::string& target_plugin_id, uint16_t target_version_major,
256 uint16_t target_version_minor, uint8_t log_level);
259 Handle load_and_create(
const std::string& plugin_id,
const std::string& lib_name, uint16_t
version_major,
260 uint16_t version_minor,
const std::string& dir_name,
261 const std::deque<std::string>& search_paths,
const std::string& function_name,
262 std::shared_ptr<PluginEntry>* plugin_entry);
264 bool unload(
const std::string& plugin_complex_id);
266 bool has_loaded(
const std::string& plugin_complex_id);
268 static bool destroy(std::shared_ptr<PluginEntry> plugin_entry,
Handle handle,
272 std::unique_ptr<Impl> impl_;
283 const std::string& dir_name,
const std::deque<std::string>& search_paths,
284 const std::string& function_name) {
285 static_assert(!T::get_plugin_id().empty(),
"Plugin id can not be empty.");
287 std::shared_ptr<PluginEntry> plugin_entry;
288 auto* handle = load_and_create(T::get_plugin_id().data(), lib_name,
version_major, version_minor, dir_name,
289 search_paths, function_name, &plugin_entry);
295 return std::shared_ptr<T>(
static_cast<T*
>(handle), [plugin_entry = std::move(plugin_entry)](T* interface_ptr) {
296 destroy(std::move(plugin_entry), interface_ptr);
302 static_assert(!T::get_plugin_id().empty(),
"Plugin id can not be empty.");
304 return unload(get_plugin_complex_id<T>(lib_name));
309 static_assert(!T::get_plugin_id().empty(),
"Plugin id can not be empty.");
311 return has_loaded(get_plugin_complex_id<T>(lib_name));
316 static_assert(!T::get_plugin_id().empty(),
"Plugin id can not be empty.");
318 return lib_name +
"@" + T::get_plugin_id().data();
327 #if defined(_WIN32) || defined(__CYGWIN__)
328 #define VLINK_PLUGIN_EXPORT __declspec(dllexport)
330 #define VLINK_PLUGIN_EXPORT __attribute__((visibility("default")))
345 #define VLINK_PLUGIN_REGISTER(InterfaceType) \
347 static constexpr std::string_view get_plugin_id() { \
348 static_assert(std::is_abstract_v<InterfaceType>, "Plugin interface must be abstract class."); \
349 static_assert(std::has_virtual_destructor_v<InterfaceType>, "Plugin interface must have a virtual destructor."); \
350 return vlink::NameDetector::get<InterfaceType>(); \
365 #define VLINK_PLUGIN_REGISTER_BY_ID(InterfaceType, PluginID) \
367 static constexpr std::string_view get_plugin_id() { \
368 static_assert(std::is_abstract_v<InterfaceType>, "Plugin interface must be abstract class."); \
369 static_assert(std::has_virtual_destructor_v<InterfaceType>, "Plugin interface must have a virtual destructor."); \
387 #define VLINK_PLUGIN_DECLARE(ImplementType, VersionMajor, VersionMinor) \
389 VLINK_PLUGIN_EXPORT void* VLINK_PLUGIN_CREATE_FUNC_NAME(const char* lib_name, const char* plugin_id, \
390 uint16_t version_major, uint16_t version_minor, \
391 uint8_t log_level) { \
392 static_assert(std::is_default_constructible_v<ImplementType>, \
393 "Plugin implementation must have default constructible"); \
394 static_assert(!ImplementType::get_plugin_id().empty(), "Plugin id can not be empty."); \
395 static_assert(!std::is_abstract_v<ImplementType>, "Plugin implementation cannot be an abstract class."); \
398 if VUNLIKELY (!vlink::Plugin::process_plugin_internal(lib_name, ImplementType::get_plugin_id().data(), \
399 VersionMajor, VersionMinor, plugin_id, version_major, \
400 version_minor, log_level)) { \
404 return new ImplementType; \
408 VLINK_PLUGIN_EXPORT bool VLINK_PLUGIN_DESTROY_FUNC_NAME(void* handle) { \
409 if VUNLIKELY (!handle) { \
414 delete static_cast<ImplementType*>(handle); \
Level
Message severity level.
Definition: logger.h:144
Manager that loads, tracks and unloads shared-library plugins by interface type.
Definition: plugin.h:122
bool has_loaded(const std::string &lib_name)
Reports whether a plugin for interface T is currently registered.
Definition: plugin.h:308
bool unload(const std::string &lib_name)
Removes a previously loaded plugin from the registry.
Definition: plugin.h:301
void * Handle
Opaque handle to a loaded shared library; treated as a token by the public API.
Definition: plugin.h:127
static bool process_plugin_internal(const std::string &lib_name, const std::string &local_plugin_id, uint16_t local_version_major, uint16_t local_version_minor, const std::string &target_plugin_id, uint16_t target_version_major, uint16_t target_version_minor, uint8_t log_level)
Internal version/ID gate invoked from the VLINK_PLUGIN_DECLARE entry point.
std::string get_plugin_complex_id(const std::string &lib_name)
Builds the composite key used internally to identify a (library, interface) pair.
Definition: plugin.h:315
void set_log_level(Logger::Level level)
Sets the verbosity level used for plugin diagnostic messages.
~Plugin()
Destroys the plugin manager and unloads every still-resident library via clear().
Logger::Level get_log_level() const
Returns the verbosity level currently used for plugin diagnostics.
static std::deque< std::string > default_search_path()
Returns the default ordered search path used when locating plugin libraries.
std::shared_ptr< T > load(const std::string &lib_name, uint16_t version_major, uint16_t version_minor, const std::string &dir_name="", const std::deque< std::string > &search_paths=default_search_path(), const std::string &function_name=VLINK_MACRO_STRING_GET(VLINK_PLUGIN_CREATE_FUNC_NAME))
Loads a shared library that implements interface T and returns a tracked handle.
Definition: plugin.h:282
Plugin()
Constructs an empty plugin manager with no libraries loaded.
void clear()
Unloads every library currently tracked by this manager.
Singleton logger with stream / format / printf / RAII-stream entry points.
Cross-platform macros for visibility, branch hints, copy prevention, singletons and string helpers.
#define VUNLIKELY(...)
Short alias for VLINK_UNLIKELY.
Definition: macros.h:289
#define VLINK_EXPORT
Definition: macros.h:81
#define VLINK_MACRO_STRING_GET(name)
Stringifies the expanded value of a macro (two-step expansion).
Definition: macros.h:261
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174
Header-only compile-time introspection of type names and enumerator labels.
constexpr uint32_t version_major(uint32_t version) noexcept
Extracts the major component from an encoded zero-copy wire version.
Definition: header.h:115
#define VLINK_PLUGIN_DESTROY_FUNC_NAME
Symbol name of the plugin destruction entry point exported by VLINK_PLUGIN_DECLARE.
Definition: plugin.h:107
#define VLINK_PLUGIN_CREATE_FUNC_NAME
Symbol name of the plugin construction entry point exported by VLINK_PLUGIN_DECLARE.
Definition: plugin.h:101