Skip to content

QuantStack/xplugin

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();
    }
}