The purpose of this plugin is to give other plugins access to a simple add() function, which could then be used as follows:

...
#include "sampleutilities.h"
...
double addResult = Sample::add(3.0, 5.0);
...
File structure
src
 ├─ sampleglobal.h
 ├─ sampleplugin.cpp
 ├─ sampleplugin.h
 ├─ sampleplugin.json
 ├─ sampleutilities.cpp
 └─ sampleutilities.h
CMakeLists.txt
Category

The first thing we need to do is to decide on the category of our plugin (click here for some information on categories). Our plugin is aimed at helping people who want to learn how to write plugins for OpenCOR. So, it should be in the Sample category. This means that its code can be found under [OpenCOR]/src/plugins/sample/Sample/.

Interfaces

All our plugin does is to make its add() function available to other plugins, so there is no need for our plugin to interact with OpenCOR and, therefore, no need to implement any interface.

CMake project

To build our plugin, we need a CMakeLists.txt file (click here for some information on CMake and plugins in OpenCOR), which contents is:

PROJECT(SamplePlugin)

# Add the plugin

ADD_PLUGIN(Sample
    SOURCES
        ../../plugininfo.cpp

        src/sampleplugin.cpp
        src/sampleutilities.cpp
    HEADERS_MOC
        src/sampleplugin.h
    INCLUDE_DIRS
        src
    QT_MODULES
        Core
)

The first line specifies the name of the CMake project for our Sample plugin, i.e. SamplePlugin. Then, we have a call to the ADD_PLUGIN() macro (line 5), which is defined in common.cmake. Different types of parameters are passed to it (SOURCES, HEADERS_MOC, INCLUDE_DIRS, QT_MODULES and QT_LIBRARIES at lines 6, 11, 13, 15 and 17, respectively), followed by the parameters themselves.

As for any plugin, our Sample plugin must reference plugininfo.cpp (line 7), so that it can provide some basic information about itself (more on this below). .cpp files that contain the plugin's implementation code must also be referenced (lines 9 and 10). (Note that they start with sample, i.e. the name of the plugin in lower case. This convention is used throughout OpenCOR's code to ensure that there are no name clashes between plugins' files.) All header files that define at least one class that uses the Q_OBJECT macro must also be referenced. sampleplugin.h is one such file (see below) and is therefore referenced (line 12). To make it easier to write (and to maintain) #include statements, we provide src as an include directory (line 14). Finally, OpenCOR uses the Qt framework, so even though our Sample plugin is very minimal, we must reference both the Core module and the QtCore library (lines 16 and 18, respectively).

Plugin information

We want our plugin to be recognisable by OpenCOR, which means that it must provide some plugin information. sampleplugin.cpp therefore contains a C function that is called by OpenCOR to retrieve some basic information about our plugin. That function is declared in sampleplugin.h, which is also where our plugin class is defined:

#include "plugininfo.h"

//==============================================================================

namespace OpenCOR {
namespace Sample {

//==============================================================================

PLUGININFO_FUNC SamplePluginInfo();

//==============================================================================

class SamplePlugin : public QObject
{
    Q_OBJECT

    Q_PLUGIN_METADATA(IID "OpenCOR.SamplePlugin" FILE "sampleplugin.json")
};

//==============================================================================

}   // namespace Sample
}   // namespace OpenCOR

We need to know about the data structure of our basic information, so we include plugininfo.h (line 27). Then, we declare our C function (line 36). Finally, we have the definition of our plugin class (lines 40-45). The call to the Q_PLUGIN_METADATA() macro (line 44) requires to pass both an IID (OpenCOR.SamplePlugin) and the name of a JSON file (sampleplugin.json). As mentioned here, the JSON file simply references the name of our plugin class (SamplePlugin):

{
    "Keys": [ "SamplePlugin" ]
}

Next, we have our sampleplugin.cpp file, which contents is:

#include "sampleplugin.h"

//==============================================================================

namespace OpenCOR {
namespace Sample {

//==============================================================================

PLUGININFO_FUNC SamplePluginInfo()
{
    Descriptions descriptions;

    descriptions.insert("en", QString::fromUtf8("a plugin that provides an addition function."));
    descriptions.insert("fr", QString::fromUtf8("une extension qui fournit une fonction d'addition."));

    return new PluginInfo(PluginInfo::Sample, false, false,
                          QStringList(),
                          descriptions);
}

//==============================================================================

}   // namespace Sample
}   // namespace OpenCOR

We start by including our header file (line 23). Then, lines 32-42 contain the body of our C function . The first thing it does is to create an instance of Descriptions on the stack (line 34). This instance is used to provide a multilingual description of our plugin (here, both in English and in French; lines 36 and 37). Then, it creates and returns an instance of PluginInfo on the heap (lines 39-41), which contains the basic information needed by OpenCOR to identify our plugin. This includes our plugin's category (PluginInfo::Sample; line 39), whether it is selectable (false; line 39), whether it offers direct CLI support (false; line 39), our plugin's direct dependencies (none, so QStringList(); line 40) and its multilingual description (descriptions; line 41).

the returned PluginInfo object gets deleted by OpenCOR. So, no need to worry about it.

Plugin specific

Finally, we need to deal with our plugin's add() function. It is declared in sampleutilities.h:

#include "sampleglobal.h"

//==============================================================================

namespace OpenCOR {
namespace Sample {

//==============================================================================

double SAMPLE_EXPORT add(const double &pNb1, const double &pNb2);

//==============================================================================

}   // namespace Sample
}   // namespace OpenCOR

We start by including sampleglobal.h (line 27). This header file defines the SAMPLE_EXPORT macro (click here for some information on plugins' global header file in OpenCOR), which we use to declare our plugin's add() function (line 36).

The implementation our plugin's add() function can be found in sampleutilities.cpp:

#include "sampleutilities.h"

//==============================================================================

namespace OpenCOR {
namespace Sample {

//==============================================================================

double add(const double &pNb1, const double &pNb2)
{
    // Return the sum of the two given numbers

    return pNb1+pNb2;
}

//==============================================================================

}   // namespace Sample
}   // namespace OpenCOR

We start by including sampleutilities.h (line 23). Then, we have a straightforward implementation of our plugin's add() function (lines 32-37).