plugin1

Do not hesitate to rework and clean up your code! Its always good practice to rethink what you have done before because everyone is evolving and what you thought best code solution yesterday, today becomes crappiest thing ever!

To help keep your code clean and organized let me introduce Qt plugins.

There is some documentation on how to create Qt plugins on Qt official site but lets go thru all steps again to make things clear.

So, step one: define plugin’s interface:

#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H

#include <QtPlugin>

QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE

class PluginInterface
{
public:

    virtual ~PluginInterface() {}

    virtual QString name() = 0;
    virtual QString description() = 0;

};

QT_BEGIN_NAMESPACE

#define PluginInterface_iid "org.cooldev.coolapp.PluginInterface/1.0"

Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)
QT_END_NAMESPACE

#endif // PLUGININTERFACE_H

as you can see, plugin interface is pure virtual class. Macro Q_DECLARE_INTERFACE tells to Qt all that it need to create Qt plugin. For sure, PluginInterface_iid must be an unique identifier

Great news for QtCreator users. Latest QtCreator IDE has a template for creating Qt plugins: just go to File->New file or Project->Libraries->C++ Library. Press ‘Choose…’. Select Type as ‘Qt plugin’, choose an name, press Next, choose your Qt version, Next, choose your plugins class name and choose base class (any of them, you’ll remove it later). QtCreator will create an plugin implementation for you.

Make sure that your plugin implementation base classes are QObject and your interface class:

class MyFirstPlugin : public QObject, public PluginInterface {

another important thing is to put Q_INTERFACES declaration before public part of your plugin’s class declaration:

class MyFirstPlugin : public QObject, public PluginInterface {
 Q_OBJECT
 Q_INTERFACES(PluginInterface)

Now lets get back to .pro file. QtCreator will create needed lines in the file:

TEMPLATE = lib
CONFIG += plugin

Don’t forget about DESTDIR. Its important for packaging application for your destination platform

Ok. Plugin created and built. Now we have to load it from our application:

#include <QPluginLoader>

PluginLoader::load()
{
    QDir pluginsDir = QDir(qApp->applicationDirPath());
    pluginsDir.cd("plugins"); //good practice to put plugins into 'plugins' folder near your application

    foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = loader.instance();
        if (plugin) {
            PluginInterface *pluginInstance = qobject_cast<PluginInterface*>(plugin);
            if (pluginInstance) {
                qDebug() << "Plugin file " << fileName << " loaded ok.";
                // now the plugin can be initialized and used
            } else {
                qDebug() << "Plugin file " << fileName << " loading fail";
            }
        }
        else {
            qDebug() << loader.errorString();
            qDebug() << plugin;
        }
    }
}

Two main points:

  • Qt tries to load every file in ‘plugins’ folder as Qt plugin
  • with casting loaded instance to your interface class you actually checking if the plugin is implementing exact this interface

That’s it for now

ps. Plugins can be derived from QObject, which makes possible to use signal-slot conception. As usual, there some tricks need to be done:

  1. Add your new plugin interface header file to HEADERS .pro file of your plugin implementation
  2. This works only for non-static Qt builds

Leave a Reply