Skip to content

QuantStack/xplugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

dac01f2 · Mar 21, 2025

History

17 Commits
Mar 21, 2025
Aug 9, 2023
Aug 7, 2023
Aug 9, 2023
Mar 21, 2025
Mar 21, 2025
Aug 7, 2023
Aug 1, 2023
Aug 1, 2023
Mar 21, 2025
Aug 1, 2023
Aug 7, 2023
Aug 1, 2023
Mar 21, 2025
Aug 1, 2023

Repository files navigation

xplugin

ci

Generic plugin framework in C++.

Features

  • Generic plugin framework
  • Arbitrary abstract base classes can be used as plugin interface
  • Customizable with custom plugin factories (see examples)
  • Works on linux, mac, windows and emscripten

Usage

Example 1

All plugins are derived from a base class, in the first example MyPluginBase. All concrete plugins are derived from MyPluginBase and implement the pure virtual function (in this example it is only the do_something() function). Furthermore, for this example, we assume that all concrete plugins have an empty constructor. (see example 2 for a more complex example)

Define a plugin interface

my_plugin_base.hpp:

class MyPluginBase
{
public:
    virtual ~MyPluginBase() = default;
    virtual void do_something() = 0;
};

Define a plugin implementation / define multiple plugin implementations

my_plugin_a.cpp:

#include <my_plugin_base.hpp>
#include <xplugin/xfactory.hpp>

class MyPluginA : public MyPluginBase
{
    public:
    virtual ~MyPluginA() = default;
    override void do_something() override
    {
        std::cout << "MyPluginA::do_something()" << std::endl;
    }
}

using factory_type = xp::xfactory<MyPluginA, MyPluginBase>;
XPLUGIN_CREATE_XPLUGIN_FACTORY(factory_type);

my_plugin_b.cpp:

#include <my_plugin_base.hpp>
#include <xplugin/xfactory.hpp>

class MyPluginB : public MyPluginBase
{
    public:
    virtual ~MyPluginB() = default;
    override void do_something() override
    {
        std::cout << "MyPluginB::do_something()" << std::endl;
    }
}

using factory_type = xp::xfactory<MyPluginB, MyPluginBase>;
XPLUGIN_CREATE_XPLUGIN_FACTORY(factory_type);

3. Use the plugin

main.cpp:

#include <my_plugin_base.hpp>
#include <xplugin/xplugin_registry.hpp>
#include <xplugin/xfactory.hpp>


#include <iostream> // just for the example

using factory_base_type = xp::xfactory_base<MyPluginBase>;
using plugin_registry_type = xp::xplugin_registry<factory_base_type>;


int main(int argc, char** argv)
{

    if(argc != 2){
        std::cout << "usage: " << argv[0] << " <plugin_directory>" << std::endl;
        return 1;
    }
    std::string plugin_directory = argv[1];


    plugin_registry_type registry(plugin_directory);

    for (auto [name, factory] : registry){
        std::cout << name << std::endl;
        auto plugin = factory->create();
        plugin->do_something();
    }
}

Example 2

We again define a plugin interface MyOtherPluginBase and a concrete plugin implementations MyOtherPluginA and MyOtherPluginB. The difference to the first example is that the concrete plugins have a constructor with arguments. But both plugins have the same constructor signature.

my_other_plugin_base.hpp:

class MyOtherPluginBase
{
public:
    virtual ~MyOtherPluginBase() = default;
    virtual void do_something() = 0;
};

my_other_plugin_a.cpp:

#include <my_plugin_base.hpp>
#include <xplugin/xfactory.hpp>

class MyOtherPluginA : public MyPluginBase
{
    public:
    MyOtherPluginA(int some_data, const std::string  & some_other_data)
    : m_some_data(some_data)
    , m_some_other_data(some_other_data)
    {}

    virtual ~MyOtherPluginA() = default;
    override void do_something() override
    {
        std::cout << "MyOtherPluginA::do_something()" << std::endl;
        std::cout << "some_data: " << m_some_data << std::endl;
        std::cout << "some_other_data: " << m_some_other_data << std::endl;

    }
    private:
    int m_some_data;
    std::string m_some_other_data;
}

using factory_type = xp::xfactory<MyOtherPluginA, MyPluginBase, int, const std::string &>;
XPLUGIN_CREATE_XPLUGIN_FACTORY(factory_type);

my_other_plugin_b.cpp:

#include <my_plugin_base.hpp>
#include <xplugin/xfactory.hpp>

class MyOtherPluginB : public MyPluginBase
{
    public:
    MyOtherPluginB(int some_data, const std::string  & some_other_data)
    : m_some_data(some_data)
    , m_some_other_data(some_other_data)
    {}

    virtual ~MyOtherPluginB() = default;
    override void do_something() override
    {
        std::cout << "MyOtherPluginB::do_something()" << std::endl;
        std::cout << "some_data: " << m_some_data << std::endl;
        std::cout << "some_other_data: " << m_some_other_data << std::endl;

    }
    private:
    int m_some_data;
    std::string m_some_other_data;
}

using factory_type = xp::xfactory<MyOtherPluginB, MyPluginBase, int, const std::string &>;
XPLUGIN_CREATE_XPLUGIN_FACTORY(factory_type);

main.cpp:

#include <my_plugin_base.hpp>
#include <xplugin/xplugin_registry.hpp>
#include <xplugin/xfactory.hpp>


#include <iostream> // just for the example

using factory_base_type = xp::xfactory_base<MyOtherPluginBase, int, const std::string &>;
using plugin_registry_type = xp::xplugin_registry<factory_base_type>;

int main(int argc, char** argv)
{

    if(argc != 2){
        std::cout << "usage: " << argv[0] << " <plugin_directory>" << std::endl;
        return 1;
    }
    std::string plugin_directory = argv[1];


    plugin_registry_type registry(plugin_directory);

    int some_data = 42;
    std::string some_other_data = "Hello World";

    for (auto [name, factory] : registry){
        std::cout << name << std::endl;
        auto plugin = factory->create(some_data, some_other_data);
        plugin->do_something();
    }
}