Plugin System

[中文]

Public header: #include "brookesia/lib_utils/plugin.hpp"

Overview

plugin provides a generic plugin registry and instance management: register, discover, and create plugins by name.

Features

  • Template registration and lookup by name

  • Lazy instantiation and singleton registration

  • Enumerate, release, and cleanup

  • Macros for registration symbols and link visibility

API Reference

Header File

Classes

template<typename T>
class PluginRegistry

Thread-safe registry for named plugin factories and cached instances.

Template Parameters

T -- Base class type exposed by the registry.

Public Static Functions

static inline std::shared_ptr<T> get_instance(const std::string &name)

Get a plugin instance by name.

Returns the cached instance when available, otherwise creates it through the registered factory.

Note

The returned shared_ptr shares ownership with the Registry. The instance remains valid as long as either the Registry or any returned shared_ptr holds a reference, ensuring thread-safe access even if release_instance() or remove_plugin() is called.

Parameters

name -- [in] Registered plugin name.

Returns

Shared pointer to the plugin instance, or nullptr when the plugin is not registered or the factory is empty.

static inline std::map<std::string, std::shared_ptr<T>> get_all_instances()

Get instances for all registered plugins.

Missing cached instances are created on demand before they are returned.

Note

Each returned shared_ptr shares ownership with the Registry. The instances remain valid as long as either the Registry or any returned shared_ptr holds a reference, ensuring thread-safe access.

Returns

Map from plugin name to shared plugin instance.

static inline size_t get_plugin_count()

Get the number of registered plugin names.

Returns

Total number of registered plugins.

static inline bool has_plugin(const std::string &name)

Check whether a plugin name is registered.

Parameters

name -- [in] Plugin name to test.

Returns

true when the plugin exists in the registry, or false otherwise.

static inline void release_instance(const std::string &name)

Release the cached instance for a registered plugin.

This keeps the factory registration intact and only drops the registry-held shared pointer.

Parameters

name -- [in] Plugin name.

static inline void release_all_instances()

Release all cached plugin instances without removing registrations.

static inline void remove_plugin(const std::string &name)

Remove a plugin registration and its cached instance.

Parameters

name -- [in] Plugin name to remove.

static inline void remove_all_plugins()

Remove all registered plugins and cached instances.

template<typename PluginType>
static inline void register_plugin(const std::string &name, FactoryFunc factory)

Register a plugin factory under a unique name.

Template Parameters

PluginType -- Concrete plugin type being registered.

Parameters
  • name -- [in] Plugin name. Existing registrations with the same name are kept unchanged.

  • factory -- [in] Factory used to lazily create instances.

Macros

_BROOKESIA_PLUGIN_CONCAT(a, b)
BROOKESIA_PLUGIN_CONCAT(a, b)
BROOKESIA_PLUGIN_CREATE_SYMBOL(symbol_name, static_var_name)

Create a linker-visible symbol that keeps a registrar object alive.

Note

The function is defined outside any namespace to ensure proper linking. The static variable reference ensures the registrar instance is not optimized away.

BROOKESIA_PLUGIN_REGISTER_PRE_MAIN_FUNCTION(symbol_name, function)

Auto-register a function to be invoked before main().

Generates a file-local static registrar whose constructor calls function exactly once during C++ static initialization - i.e. before the program enters main(). On ESP-IDF this also guarantees the function runs before app_main() is entered.

Typical use cases: plugin auto-registration, installing HAL hook callbacks, seeding global singletons, or any one-shot boot-time setup. This macro is the building block behind every other BROOKESIA_PLUGIN_REGISTER_* form.

Relative ordering between translation units that use this (or any other static initialization) is unspecified. If ordering matters, embed it inside function itself.

The generated static instance is also exported as an external symbol via BROOKESIA_PLUGIN_CREATE_SYMBOL so the linker keeps it alive when this TU lives in a static library. Remember to add -u <symbol_name> to the final link.

static void boot_time_setup() {
    // Runs before main / app_main.
}
BROOKESIA_PLUGIN_REGISTER_PRE_MAIN_FUNCTION(my_boot_setup_sym, boot_time_setup);

BROOKESIA_PLUGIN_REGISTER_PRE_MAIN_FUNCTION(my_inline_sym, [](){
    // ... inline pre-main work ...
});

Parameters
  • symbol_name -- Linker-visible identifier used with -u to keep the registrar alive.

  • function -- Callable expression (return value is ignored); typically a function pointer or a capture-less lambda.

BROOKESIA_PLUGIN_REGISTER_WITH_CONSTRUCTOR(BaseType, PluginType, name, creator, symbol_name)

Register a plugin using a custom creator expression.

Note

Automatically creates a fixed symbol name based on PluginType for linker -u option. Internally delegates to BROOKESIA_PLUGIN_REGISTER_PRE_MAIN_FUNCTION for the static-init dispatch; the only extra machinery here is the pointer-type-coercion helper that adapts shared/unique pointers returned by the creator into the registry's shared_ptr<BaseType> factory signature.

Parameters
  • BaseType -- Registry base type.

  • PluginType -- Concrete plugin type to register.

  • name -- Plugin name used by PluginRegistry.

  • creator -- Creator expression returning shared_ptr or unique_ptr compatible with the registry.

  • symbol_name -- Linker symbol exported for -u.

BROOKESIA_PLUGIN_REGISTER(BaseType, PluginType, name, ...)

Register a plugin constructed with std::make_shared.

// Example usage:
BROOKESIA_PLUGIN_REGISTER(BaseService, MyPlugin, "my_plugin");
BROOKESIA_PLUGIN_REGISTER(BaseService, MyPlugin, "my_plugin", arg1, arg2);

Parameters
  • BaseType -- Registry base type.

  • PluginType -- Concrete plugin type to register.

  • name -- Plugin name used by PluginRegistry.

  • ... -- Optional constructor arguments forwarded to PluginType.

BROOKESIA_PLUGIN_REGISTER_SINGLETON(BaseType, PluginType, name, instance_expr)

Register a singleton object in the plugin registry.

This macro allows registering a singleton instance to the plugin registry. It uses a custom no-op deleter to prevent the shared_ptr from destroying the singleton. Automatically generates a fixed symbol name based on PluginType for linker -u option.

// Example usage:
BROOKESIA_PLUGIN_REGISTER_SINGLETON(
    BaseService,
    MySingleton,
    "my_singleton",
    MySingleton::get_instance()
);
// Creates symbol: _MySingleton_symbol_<line_number>
// Use: target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _MySingleton_symbol_<line_number>")

Parameters
  • BaseType -- Registry base type.

  • PluginType -- Singleton type to register.

  • name -- Plugin name used by PluginRegistry.

  • instance_expr -- Expression that yields a singleton instance reference, for example Type::get_instance().

BROOKESIA_PLUGIN_REGISTER_WITH_SYMBOL(BaseType, PluginType, name, symbol_name, ...)

Register a plugin constructed with std::make_shared and a custom linker symbol.

// Example usage:
BROOKESIA_PLUGIN_REGISTER_WITH_SYMBOL(BaseService, MyPlugin, "my_plugin", "custom_symbol_name");
BROOKESIA_PLUGIN_REGISTER_WITH_SYMBOL(BaseService, MyPlugin, "my_plugin", "custom_symbol_name", arg1, arg2);
// Use: target_link_libraries(${COMPONENT_LIB} INTERFACE "-u custom_symbol_name")

Parameters
  • BaseType -- Registry base type.

  • PluginType -- Concrete plugin type to register.

  • name -- Plugin name used by PluginRegistry.

  • symbol_name -- Custom linker symbol exported for -u.

  • ... -- Optional constructor arguments forwarded to PluginType.

BROOKESIA_PLUGIN_REGISTER_SINGLETON_WITH_SYMBOL(BaseType, PluginType, name, instance_expr, symbol_name)

Register a singleton object with a custom linker symbol.

This macro allows registering a singleton instance to the plugin registry. It uses a custom no-op deleter to prevent the shared_ptr from destroying the singleton. Uses the provided custom symbol name for linker -u option.

// Example usage:
BROOKESIA_PLUGIN_REGISTER_SINGLETON_WITH_SYMBOL(
    BaseService,
    MySingleton,
    "my_singleton",
    MySingleton::get_instance(),
    "custom_symbol_name"
);
// Use: target_link_libraries(${COMPONENT_LIB} INTERFACE "-u custom_symbol_name")

Parameters
  • BaseType -- Registry base type.

  • PluginType -- Singleton type to register.

  • name -- Plugin name used by PluginRegistry.

  • instance_expr -- Expression that yields a singleton instance reference.

  • symbol_name -- Custom linker symbol exported for -u.