One hundred reasons my Qt plugin is not working

Author: David Garcia Garzon / Wiki source

When I was developing widgets plugins for Qt Designer, I encountered too many of reasons for a plugin to not work properly. Even worse, all that reasons are really obscure and silent. Designer, at least in its vanila version, doesn't offer any hint why it is not loading a given plugin. This article tries to give some light to those reasons and gives some tricks to spot them.

The context of this article is Qt4 and Linux. Feel free to send me your own experiences on other contexts.

A symbol is missing

This error should be the first to be explained because a symbol missing in the plugin is so common and you won't get any feedback when it happens. When you build the plugin, the linker won't complaint about missing symbols as it is a dynamic library pending to be linked on runtime. Later, when the plugin host (either designer or a QUiLoader based app) tries to load it and fails, it does not complain at all neither. Just that the plugin won't be available but no error message is displayed.

Fortunately there is a quick way of checking if this is happening. Just build an empty main function like this:

// plugintest.cxx
int main() { return 0; }

and do:

$ g++ plugintest.cxx libMyPlugin.so

If the linker complains about missing symbols, those missing symbols are the ones preventing the plugin to load.

Remember that Qt plugins must be linked to any symbols they use. So you must link also: the cxx of the widget (the plugin cxx is not enough) the moc of the widget (even if the plugin is just a hxx it may generate a moc cxx) any link dependency of the widget any library needed by your plugin (this includes Qt ones; if you use QtOpenGL for example, don't miss it!)

Not at the proper path

The plugin must be in some place that designer or a QUiLoader based app could find it. Of course, no message will be given to you if you place it in the wrong location.

There is a good way to check whether you are not placing the plugin on the proper location. Take some of the plugins designer already loads (see About/Plugins) and move it to the location you are placing your own widget. If you stop seeing it, you have a location problem.

Hosts search for plugins in a sequence of locations. Designer plugins must be placed inside the 'designer' folder within such location. For example, if the host looks for plugins at /some/location/for/plugins, designer plugins should be at /some/location/for/plugins/designer. So don't forget the designer folder!

Which are those locations?

The first location is the standard path where the plugins are placed on your system. Normally at $QTDIR/plugins, which depends on the actual value of QTDIR environment variable in your system. So the final path for your widgets plugin libMyPlugin.so will be $QTDIR/plugins/designer/libMyPlugin.so If you don't know where the QTDIR var points to, just look for some plugin that comes with Qt such as libqt3supportplugin.so.

The second location to place the plugin is in the same path where the host is. So, if you binary is in /some/path/hostbinary, the designer plugin you should be at /some/path/designer/libMyPlugin.so. In Unix, this is not useful to run Designer because you cannot place a 'designer' folder in the same folder that the 'designer' binary is. But it is very useful for a host application while you are developing it, because you don't have to install the plugin as root every time.

Finally, qt uses an environment variable named 'QT_PLUGIN_PATH'. It contains a list of plugin directories using the same syntax than the PATH variable in your system, that is separated by colons in Linux and semicolons in windows. Beware that such paths should be the ones without the 'designer' folder. If you place your plugin at /the/location/designer/libMyPlugin.so, the QT_PLUGIN_PATH should contain /the/location without the designer path.

If you don't want to rely on those paths you can force a path using QCoreApplication::addLibraryPath or QUiLoader::addPluginPath. See QCoreApplication and QUiLoader API's for details.

If you want to know the complete list of paths your plugins are being searched in execute the following code in your host:

QStringList paths = QCoreApplication::libraryPaths();
for (QStringList::iterator it = paths.begin(); it!=paths.end(); it++)
{
    std::cout
        << "Looking for plugins at path: "
        << it->toStdString() << std::endl;
}

Coliding libraries

Because different locations are available, is common that different versions of the library are placed in different places. This generates no problem when they are the same version. But when different versions are available all of them are loaded.

To spot this reason, remove the library. If after that it still loads, it is loading a dupped library anywhere else.

Not the proper compilation mode

Double check whether you are compiling with the same Qt debug or Qt release mode than the host application. Normally designer is compiled in release mode, that means that your plugin and your host should be both compiled with the -DQT_NO_DEBUG option enabled and that they must be linked against the release version of the Qt libraries. Note that debug version of Qt4 libraries normally has a suffix ('d' on windows, or '_debug' in linux).

In Linux, you can use the ldd command to list the libraries a built binary is linking to.

Bad init xml

Maybe your plugin loads but you don't see some of the widgets. Note that if you do not return a correct xml on the reimplementation of the QDesignerCustomWidgetInterface::domXml method, your widget may be instanciated but it won't appear on the designer widget toolbox.

That means that an .ui file containing the widget will display it properly but that the widget toolbox has no entry to add it. So, the spotting procedure is a little trickier:

  • build an ui file with some working Qt plugin widget (not the standard widgets, but a qt3suport or an arthur one, which are plugins),
  • edit the xml by hand, changing the inserted widget class by the one not appearing ** Note: You should change it in two places, the custom widget declaration and the widget you inserted
  • if you load the ui on the designer and it appears, then the xmlDom is wrong.

Missing Q_OBJECT

Sometimes your plugin loads well and you can even use it from the designer. But once you save the .ui file and you try to load it again, you see that your widget has promoted to some base class such as QWidget, loosing any any specific properties.

This is a symptom that you didn't place the Q_OBJECT macro on the widget class declaration.

A widget without Q_OBJECT macro in its declaration may work properly. It just uses the Metaobject information of the base class. But designer uses such metaobject information to writedown the ui file. It takes the class name, the properties... But the metaobject information says that it is a QWidget and not YourWidget and this is what the ui file will contain. When you load it, any trace of YourWidget has dissapeared.

Things that do not interfer plugin loading

While trying to find out the reasons the plugins don't load, I also tried some apparent failure reasons. After having the plugin working i tried again most of the hypothesis. Here is a list with the things that do not interfere with the loading. (Tested just in Linux)

  • You can change the name of the library
  • You can even avoid using the 'lib' prefix (but the '.so' suffix is mandatory)
  • You can duplicate the library, on different locations or names as long as they are the same version
  • You can use whatever name as the first argument for the Q_EXPORT_PLUGIN2 macro

Conclusions

Qt comes with a lot of examples that work out the box. But as soon you try to modify them, you come up with those problems. This is more noticeable, when you are using a different build chain than qmake as it was my case.

Of course that 'a hundred reasons' was an exaggeration. But when you have no feedback on what's happening even one reason is worth ten. It would be nicer that Qt would give you some kind of warning when any of the problems is happening, such as the missing symbols or the bad xml one. Meanwhile, I hope the insight collected in this article will help you to solve your Qt plugins problems.