Managing Plugins

Writing a Plugin

A plugin in Yehia is, an instance of the Yehia::Plugin class that is created by a dynamically loaded shared library.

Now, how does one create such a module? The module must contain a function:

extern "C" Yehia::Plugin * ucxx_name_plugin_init (manager); 
Yehia::PluginManager *  manager ;

Here name is the basename of the shared library module, e.g. gql for the filename gql.la. This function must return a pointer to a referenced, managed instance of a subclass of Yehia::Pluginplugin. Referenced, in this context, means "having a reference count 1", managed means that the function SigC::manage must have been called on it.

Now that we know about the requirements for such a module, we can actually put one together, implementing our first Yehia plugin. As simple example, we will implement the famous "Hello World" program, using a plugin for output.

First, we have to define the interface to our plugin. This will be a class with several pure virtual functions that the actual plugin implementation will provide. Our greeter plugin needs just one method:

class Greeter
{
  public:
    virtual void greet(const std::string& msg) = 0;
};
	

We could have made Greeter a subclass of Yehia::Plugin, but this way we keep the greeter interface cleanly separate (you could also want use an existing interface).

Now we are ready to implement our actual plugin class. It is derived from Yehia::Plugin as well as Greeter and implements the necessary functions from both classes:

class SimpleGreeter : public Yehia::Plugin, Greeter
{
  public:
    SimpleGreeter(Yehia::PluginManager& mgr) : Yehia::Plugin(mgr) { }
    // inherited from Yehia::Plugin
    virtual std::string description() const { 
      return "A simple greeter using stdout";
   }
  // inherited from Greeter
  virtual void greet(const std::string& msg) {
    std::cout << msg << endl;
  }
};
	

The initialization function is even easier to write. Let's say we call our plugin stdout_greet, then the init function will look like this:

extern "C" Yehia::Plugin *yehia_stdout_greet_plugin_init(Yehia::PluginManager *mgr)
{
  Yehia::Plugin *plugin = SigC::manage(new SimpleGreeter(*mgr));
  plugin->reference();
  return plugin;
}
	

This is all code that is needed for the plugin. However, one might want to put the class into the anonymous namespace to make only the init function visible from the outside.

Furthermore, the plugin must be installed, to be of any use. This issue is treated in Section , “Plugins and the Filesystem”.

Plugins and the Filesystem

Plugins must be loaded from somewhere. Normally, this will be the filesytem[1]. All the plugin loaders that come with Yehia are using the filesystem. Now, which directories does Yehia use for its plugins? Well, the answer is not as simple as you might expect.

Yehia defines two lists of directories in which it looks for plugins: The list of architecture dependent paths (for plugins that are architecture-dependent, i.e. are only suited for a specific (set of) processor(s)). This is what the default loader uses. The other list is for architecture-independent plugins, like, for example, Python code.

The architecture-dependent directory list by default consists of:

  • ~/lib/yehia-devbranch/plugins

  • prefix/lib/yehia-devbranch/plugins

The architecture-independent list defaults to:

  • ~/share/yehia-devbranch/plugins

  • prefix/share/yehia-devbranch/plugins

In the above pathnames, @prefix@ is the installation prefix of Yehia (e.g. /usr/local), devbranch is the current branch name of Yehia, consisting of its major and minor version, seperated by a dot (e.g. 0.5) and "~", as usual, means the home directory (i.e. the contents of the environment variable HOME). Note that if $HOME is not set, the first item of the above lists is omitted.

You can change the default paths by setting the environment variables YEHIA_ARCH_DEP_PLUGIN_PATH and YEHIA_ARCH_INDEP_PLUGIN_PATH, for the architecture dependent and independent paths, respectively.

How the default plugin loader uses the filesystem

As described in Section , “The Plugin Namespace”, the plugin namespace is hierarchical, just as the filesystem, so the plugin name can be mapped onto a file name. This is done by simply substituting each dot in the plugin name with a slash, so gql.drivers.mysql would become gql/drivers/mysql.

The default plugin loader now takes this transformed name and in turn appends it to each of the elements of the architecture dependent path, and checks for a shared library with that name, for example for ~/lib/yehia-version/gql/drivers/mysql.so on a Linux system.

Loading and Releasing Plugins

As already explained, Yehia uses plugin loaders to perform the actual work of loading a plugin. If you try to load a plugin, each registered plugin loader is tried, until one one succeeds loading the plugin (otherwise, the plugin doesn't exist in the scope of the registered plugin loaders).

You load and release plugins using the PluginManager, which is a singleton.

Staying up to date



[1] It is perfectly possible, however, to implement a plugin loader that loads a plugin from a database, or even downloads one from the Internet).