Extendable Plugins

There are times when you will want to create a plugin that acts as a base for another plugin. GPlugin accommodates this, but there are a number of things that you as the author of an extendable plugin will have to do.

Note: This tutorial is meant for authors of native plugins. While it is possible to extend non-native plugins, it is outside the scope of this document.

Plugin Adjustments

The first and most important thing that needs to be done for this is to set the GPluginPluginInfo:bind-global property to TRUE for the GPluginPluginInfo that you return from the query method of your plugin.

This allows other plugins to be able to see the symbols in your plugin. By default, the symbols defined in plugins are not bound globally so other plugins will not see them. This explicitly changes that behavior so that other plugins can interact with your plugin.

Note: This means all symbols from your plugin that are not static, including ones pulled in from libraries, will be visible to all other plugins and the application that GPlugin is being used in.

If you have some symbols you would like to not expose you can prefix them with the G_GNUC_INTERNAL macro.

Once all of this is done there’s nothing else that should need to happen to your plugin code itself.

Build System Adjustments

Just like when you build a shared library you will need to install your header files in a location that dependent plugins are able to find them. This will of course depend on your build system, but if you’re using meson you will want to look at the install_headers function.

Likewise you will also want to create a pkg-config pc file so that other plugins can find your header files easily. There’s a module in meson that you can use for this as well.

Note: You do NOT want to enter anything for the libraries field in the pc file. Doing so will link to the library at linking time instead of during runtime which is explicitly what you need. GPlugin will resolve this by loading all dependent plugins before loading the plugin that depends on them.

GObject Introspection

You may also want to generate GObject Introspection repository and type lib files to allow plugins written in other languages to extend your plugin or to create documentation with gi-docgen.

The native plugins have to register dynamic types which is incompatible with how g-ir-scanner works when it is creating your gir and type lib files. To make this work, there is a static library provided with GPlugin named gplugin-introspection. You can use this static library to build an executable that will be called by g-ir-scanner with everything setup for you. You should be able to find it using pkg-config in your build system.

In most cases you’ll just need to load a single plugin, and you can do that via gplugin_introspection_introspect_plugin(). You’ll need to pass in your argc and argv for argument handling as well as the filename of the plugin you want to load. In this example we pass PLUGIN_FILENAME in from the build system as that knows the correct filename for the platform that we are building for.

#include <glib.h>

#include <gplugin-introspection.h>

int
main(int argc, char *argv[]) {
    return gplugin_introspection_introspect_plugin(&argc, &argv,
                                                   PLUGIN_FILENAME);
}

If for some reason you need to load multiple plugins you can use gplugin_introspection_introspect_plugins() instead. This works the same as gplugin_introspection_introspect_plugin() except it takes multiple plugin filenames that must be terminated by a NULL.

#include <glib.h>

#include <gplugin-introspection.h>

int
main(int argc, char *argv[]) {
    return gplugin_introspection_introspect_plugins(&argc, &argv,
                                                    PLUGIN1_FILENAME,
                                                    PLUGIN2_FILENAME,
                                                    NULL);
}

Once this is all setup, you’ll need to tell g-ir-scanner to use this executable. In meson, this is done by passing the executable target as the first argument to gnome.generate_gir. If you are calling g-ir-scanner directly, you will need to use the --program option instead of the --library option.