Elm  1.0
ELM is a library providing generic data structures, OS-independent interface, plugins and XML.
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Plugins

Classes

class  elm::sys::Plugger
 
class  elm::sys::Plugin
 

Detailed Description

Using a Plugin

ELM provides classes to implement plugins in an OS-indepedent way. To work-around found on some OS, ELM provides also an independent way to optionaly represent dependencies between plugins based on textual file with ".ini" syntax.

A plugin is a piece of code that provides some service while the plugger allows to plug many different plugins to implement this service.

In ELM, the plugger is declared with a hook - an identifier allowing an application to have different kinds of services and matching plugins - and a version for the current implemented plugin interface. For example, below, the plugger provides "net_plugin" services at version 1.0.0 (see elm::Version for more details). We may also gives a list of directories to look to find the plugin.

#define NET_HOOK net_plugin
elm::system::Plugger net_plugger(#NET_HOOK, Version(1, 0, 0), ".:/usr/local/net_plugins");

To open a specific plugin named, for example, "my_net_plugin", we have only to call the method Plugger::plug().

elm::system::Plugin *plugin = net_plugger.plug("my_net_plugin");

If the plugin is found, is loadable and has a compatible version, it is loaded, initialized and its instance is returned. If there is an error, a null pointer is returned and the method Plugger::lastErrorMessage() may give some information about the error.

if(plugin == NULL)
cout << "ERROR: " << plugger.lastErrorMessage() << io::endl;

Having just a plugin pointer does not provide any service. To do this, we have usually to define an interface that is implemented by the plugin instance. Let's call it "NetPlugin": it must be derived from the elm::system::Plugin class. Notice that the interface pass the right name of the service but should not pass the version. Otherwise, the service version would be ever compatible while the actual binary would be compiled for an incompatible version.

class NetPlugin: public Plugin {
public:
NetPlugin(const make& maker): Plugin(make(name, version))
{ }
virtual void performService(void) = 0;
};

Then, we can cast the plugin to its required interface and we can call the service:

NetPlugin *net_plugin = static_cast<NetPlugin *>(plugin);
net_plugin->performService();

When the plugin is no more needed, we can simply unplug it:

net_plugin->unplug();

Creating Plugins

To create a plugin, we have to define a class implementing the service interface of the plugger to plug to. Let's continue the example started in the previous section. Notice that we must implement the pure virtual functions of the interface in order to be able to create an instance of the plugin class.

class MyNetPlugin: public NetPlugin {
public:
MyNetPlugin(void);
virtual void performService(void);
};

Then, the constructor must pass to the elm::system::Plugin class the name of the service to be hooked to the right plugger with the service version supported by the plugin.

MyNetPlugin::MyNetPlugin(void): NetPlugin(make("my_net_plugin", Version(1, 0, 0))) {
}

Notice how the version is encoded in the plugin code. If this plugin is then used with in incompatible version of the plugger, say 1.2.0. The compatibility comparison will compare the version 1.0.0 (from the plugin) with the version 1.2.0 (from the plugger) and will detect possible binary incompatibility and prevent the invalid linkage.

Then we need to provide a hook to let the plugger found the plugin object.

ELM_PLUGIN(MyNetPlugin, NET_HOOK);

The result source must then be compiled to produce a shared code with your preferred compiler For example, with GCC on a Unix OS.

gcc -shared -o my_net_plugin.so my_net_plugin.cpp

ELD Files

ELM Linkage Description (ELD) files allows to circumvent limitations found on some OSes. Basically, ELD files are textual files with ".eld" extension implementing the ".ini" file syntax. They must placed in the same directory as the plugin they apply to and get the same name as the plugin with the plugin extension replaced by ".eld".

As usual ".ini" files, they can contain as many sections as possible but ELM is only interested in the "elm-plugin" section that may contain the following definitions:

"path" definition allows to cope with the lack of support for symnolic links on some OSes.

"rpaths" and "libs" are used to handle easily dependencies between plugins and libraries when the OSes does not support linkage lookup path encoded in executable.

Paths found in "path", "libs" and "rpaths" can be prefixed by "$ORIGIN" that is replaced, at run time, by the path of the directory containing the considered plugin.

Below is an example of ELD files for our example requiring two other libraries that should be found in the directory containing the plugin or in directory "/usr/lib". It is named "net_plugin.eld" and put in the same directory as "net_plugin.so".

[elm-plugin]
libs=libxml2;libxslt
rpath=$ORIGIN;/usr/lib

Below another example allows to have an alias, "net_plugin_v2" to "net_plugin". The file is named "net_plugin_v2.eld":

[elm-plugin]
path=$ORIGIN/net_plugin

This last example links with library libxml2 from the OS path:

[elm-plugin]
libs=libxml2

Old-Style Plugin Creation

The old-style plugin creation remains supported but is marked as deprecated.

Here, the plugin of the example must be declared with:

class MyNetPlugin: public NetPlugin {
public:
MyNetPlugin(void): NetPlugin("my_net_plugin", Version(1, 0, 0)) {
_description = "my plugin";
_licence = "my licence";
}
virtual void performService(void);
};

Notice how description and license were passed in the constructor.

The second difference stands in the way to declare the hook (it has proven to no robust enough):

MyNetPlugin NET_HOOK;
MyNetPlugin& my_net_plugin = NET_HOOK;