This section describes the internals of a plugin, including how it interfaces to the core simulator.
The interface to plugins is through C++ derived classes, virtual functions, and a dispatcher.
There are several types of plugins. The type is determined by the base class that is used. When a plugin is loaded, a single static object is created, and registered with a dispatcher. The dispatcher allows a lookup by name.
Plugin types may include:
It is intended that the entire interface, all models, and almost all functionality will determined by plugins.
Most plugins will create new subtypes of something. To explain how it works, I will use parameter functions as an example.
We have a base class:
class FUNCTION { public: virtual double eval(double arg)const = 0; };
This is in a header file “u_function.h”
This base class is simple. It has one member function, which a number as input, performs some operation on it, and returns the result.
Let's make a function to take the absolute value of a numeric argument, as a plugin. You need to include the header:
#include "u_function.h"
Then make a derived class, and create one instance of it.
class abs : public FUNCTION { public: std::string eval(double arg)const { return std::abs(arg); } } p;
Now, register it with the dispatcher so we can find it:
DISPATCHER<FUNCTION>::INSTALL d1(&function_dispatcher, "abs", &p);
If you want to also access it by another name, you can do that too:
DISPATCHER<FUNCTION>::INSTALL d2(&function_dispatcher, "absolute_value", &p);
That's all. The names of the class and instances don't matter because they are local to the plugin. You find it through the dispatcher, with the name you use to INSTALL it. In this case, either “abs” or “absolute_value” will find this plugin.
If you want to also be able to static-link this plugin, enclose the class and dispatcher installs in an anonymous namespace.
Here's an example of another one with the same base, all together so you can see it as a unit:
#include "u_function.h" class square : public FUNCTION { public: std::string eval(double arg)const { return arg * arg; } } p; DISPATCHER<FUNCTION>::INSTALL d1(&function_dispatcher, "square", &p);
That's all!
The procedure for compiling it is system dependent, and is usually set up when you install the main simulator.
In general, you need to make a “shared object” or “dynamic link” module.
On Linux, usually this works:
g++ -shared -fPIC -o outfile.so infile.cc
This take a source file “infile.cc”, and generates a plugin file “outfile.so”.
Then you can load it:
gnucap> load ./outfile.so