The example lives in example/plugin/ in the source tree. This page covers the host side: the extension point every plugin implements.

Build it with -DEXAMPLE=ON; the driver is testShape.

Shape.hh — the interface

// SPDX-License-Identifier: MIT
#pragma once

#include <ostream>
#include <plugin/Plugin.hh>

namespace plugin {
namespace example {

    class Shape : public Plugin< Shape >
    {
    public:
        Shape() = default;

        virtual void setSize( unsigned int value )         = 0;
        virtual unsigned int getSize() const               = 0;
        virtual void printOn( std::ostream& stream ) const  = 0;
    };

}  // namespace example
}  // namespace plugin

inline std::ostream& operator<<( std::ostream& stream, plugin::example::Shape& object )
{
    object.printOn( stream );
    return stream;
}
  • : public Plugin< Shape > — the CRTP hook. Shape now has the static create, load and catalog from plugin::Plugin.
  • Three pure virtuals — the contract a plugin fills. Nothing else is exposed.
  • Free operator<< — plain C++, not part of the plugin machinery. It just forwards to printOn, so std::cout << *shape works in the driver.

This header is compiled into the host and into every plugin .so — it is the plugin SDK.

Shape.cpp — the catalog definition

// SPDX-License-Identifier: MIT
#include "Shape.hh"

#include <plugin/PluginCatalog.hh>

CREATECATALOG( plugin::example::Shape );

One line. CREATECATALOG expands to the definition of Plugin<Shape>::catalog() — a function returning a function-local static PluginCatalog<Shape>. It is here, in a .cpp the host links, and nowhere else:

  • put it in two places → duplicate-symbol link error;
  • put it in a plugin instead → the host links nothing that defines catalog(), so it fails to link (or, if the plugin is also linked, the wrong catalog wins).

Because it is one static behind one symbol, and the loader uses RTLD_GLOBAL, every REGISTER in every loaded libShape*.so and every Shape::create in the host all touch the same map.

The CMake target

add_library( Shape SHARED Shape.cpp Shape.hh )
set_target_properties( Shape PROPERTIES
    VERSION 1.0.0 SOVERSION 1 POSITION_INDEPENDENT_CODE ON )

Shape is SHARED, not MODULE — the plugins and the driver link against it. The plugins are MODULE (next page).

Next: Three plugins.