91 #include <string_view>
101 #define VLINK_PLUGIN_CREATE_FUNC_NAME vlink_plugin_create
107 #define VLINK_PLUGIN_DESTROY_FUNC_NAME vlink_plugin_destroy
187 [[nodiscard]] std::shared_ptr<T> load(
188 const std::string& lib_name, uint16_t
version_major, uint16_t version_minor,
const std::string& dir_name =
"",
189 const std::deque<std::string>& search_paths = default_search_path(),
204 bool unload(
const std::string& lib_name);
214 [[nodiscard]]
bool has_loaded(
const std::string& lib_name);
228 [[nodiscard]] std::string get_plugin_complex_id(
const std::string& lib_name);
256 uint16_t local_version_major, uint16_t local_version_minor,
257 const std::string& target_plugin_id, uint16_t target_version_major,
258 uint16_t target_version_minor, uint8_t log_level);
261 Handle load_and_create(
const std::string& plugin_id,
const std::string& lib_name, uint16_t
version_major,
262 uint16_t version_minor,
const std::string& dir_name,
263 const std::deque<std::string>& search_paths,
const std::string& function_name,
264 std::shared_ptr<PluginEntry>* plugin_entry);
266 bool unload(
const std::string& plugin_complex_id);
268 bool has_loaded(
const std::string& plugin_complex_id);
270 static bool destroy(std::shared_ptr<PluginEntry> plugin_entry,
Handle handle,
274 std::unique_ptr<Impl> impl_;
285 const std::string& dir_name,
const std::deque<std::string>& search_paths,
286 const std::string& function_name) {
287 static_assert(!T::get_plugin_id().empty(),
"Plugin id can not be empty.");
289 std::shared_ptr<PluginEntry> plugin_entry;
290 auto* handle = load_and_create(T::get_plugin_id().data(), lib_name,
version_major, version_minor, dir_name,
291 search_paths, function_name, &plugin_entry);
297 return std::shared_ptr<T>(
static_cast<T*
>(handle), [plugin_entry = std::move(plugin_entry)](T* interface_ptr) {
298 destroy(std::move(plugin_entry), interface_ptr);
304 static_assert(!T::get_plugin_id().empty(),
"Plugin id can not be empty.");
306 return unload(get_plugin_complex_id<T>(lib_name));
311 static_assert(!T::get_plugin_id().empty(),
"Plugin id can not be empty.");
313 return has_loaded(get_plugin_complex_id<T>(lib_name));
318 static_assert(!T::get_plugin_id().empty(),
"Plugin id can not be empty.");
320 return lib_name +
"@" + T::get_plugin_id().data();
329 #if defined(_WIN32) || defined(__CYGWIN__)
330 #define VLINK_PLUGIN_EXPORT __declspec(dllexport)
332 #define VLINK_PLUGIN_EXPORT __attribute__((visibility("default")))
347 #define VLINK_PLUGIN_REGISTER(InterfaceType) \
349 static constexpr std::string_view get_plugin_id() { \
350 static_assert(std::is_abstract_v<InterfaceType>, "Plugin interface must be abstract class."); \
351 static_assert(std::has_virtual_destructor_v<InterfaceType>, "Plugin interface must have a virtual destructor."); \
352 return vlink::NameDetector::get<InterfaceType>(); \
367 #define VLINK_PLUGIN_REGISTER_BY_ID(InterfaceType, PluginID) \
369 static constexpr std::string_view get_plugin_id() { \
370 static_assert(std::is_abstract_v<InterfaceType>, "Plugin interface must be abstract class."); \
371 static_assert(std::has_virtual_destructor_v<InterfaceType>, "Plugin interface must have a virtual destructor."); \
389 #define VLINK_PLUGIN_DECLARE(ImplementType, VersionMajor, VersionMinor) \
391 VLINK_PLUGIN_EXPORT void* VLINK_PLUGIN_CREATE_FUNC_NAME(const char* lib_name, const char* plugin_id, \
392 uint16_t version_major, uint16_t version_minor, \
393 uint8_t log_level) { \
394 static_assert(std::is_default_constructible_v<ImplementType>, \
395 "Plugin implementation must have default constructible"); \
396 static_assert(!ImplementType::get_plugin_id().empty(), "Plugin id can not be empty."); \
397 static_assert(!std::is_abstract_v<ImplementType>, "Plugin implementation cannot be an abstract class."); \
400 if VUNLIKELY (!vlink::Plugin::process_plugin_internal(lib_name, ImplementType::get_plugin_id().data(), \
401 VersionMajor, VersionMinor, plugin_id, version_major, \
402 version_minor, log_level)) { \
406 return new ImplementType; \
410 VLINK_PLUGIN_EXPORT bool VLINK_PLUGIN_DESTROY_FUNC_NAME(void* handle) { \
411 if VUNLIKELY (!handle) { \
416 delete static_cast<ImplementType*>(handle); \
Level
Message severity level.
Definition: logger.h:153
Manager that loads, tracks and unloads shared-library plugins by interface type.
Definition: plugin.h:123
bool has_loaded(const std::string &lib_name)
Reports whether a plugin for interface T is currently registered.
Definition: plugin.h:310
bool unload(const std::string &lib_name)
Removes a previously loaded plugin from the registry.
Definition: plugin.h:303
void * Handle
Opaque handle to a loaded shared library; treated as a token by the public API.
Definition: plugin.h:128
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:317
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:284
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