PDA

View Full Version : QPluginLoader not recognizing a plugin



KShots
28th June 2007, 20:44
Hello all...

I've been staring at this for over an hour and I've got to admit... I'm about out of ideas.

I have a plugin (using the low-level approach) that QPluginLoader returns a NULL pointer on when instance() is called. This tends to tell me that (a) The plugin is not being built as a plugin, (b) Qt is not recognizing some name somewhere, or (c) I'm just losing my mind.

I have several other *kinds* of plugins, all of which work perfectly. This is the only plugin of its kind, so it's possible that the plugin interface is borked.

Anyways, each plugin inherits from a master plugin interface (combines common functionality into a single class which all other plugins inherit from):
class evilcpcPlugin
{
public:
virtual ~evilcpcPlugin(){}

/** Returns a short, descriptive name for this plugin*/
virtual const QString getName()const = 0;
/** Returns a longer description for this plugin*/
virtual const QString getDescription()const = 0;
/** Returns the name of the author of this plugin*/
virtual const QString getAuthor()const = 0;
/** Checks whether or not this plugin has encountered an error*/
virtual const bool isValid()const = 0;
/** Returns the nature of an error if this plugin is marked as invalid*/
virtual const QString errorString()const = 0;
/** This will return an instance of the configuration dialog for this
* plugin. Return a 0 if you need no configuration*/
virtual evilcpcPluginWidgetConfig * getConfigWidget(QWidget * parent) = 0;
/** This will return an instance of the carPC-side daemon utilized for
* remote configuration of this plugin. Return a 0 if your plugin needs
* no configuration*/
virtual evilcpcPluginWidgetConfigDaemon * getConfigWidgetDaemon(QWidget * parent) = 0;
};This base class works fine with other plugin types. The actual interface class is this:
# include <QtPlugin>
# include <evilcpcPlugin.h>

class QWidget;
class evilcpcMixerWidget;

/** This interface fills the purpose of describing and creating a given mixer
* plugin */
class evilcpcMixer : public evilcpcPlugin
{
public:
virtual ~evilcpcMixer(){}

/** Creates an widget for the mixer plugin to use. This widget will
* handle control of all audio mixer properties. This will stay
* resident at all times.
* @parent - This will be a pointer to the menu plugin's widget*/
virtual evilcpcMixerWidget * getWidget(QWidget * parent) = 0;
};

Q_DECLARE_INTERFACE(evilcpcMixer,
"com.warfaresdl.evilcpc.evilcpcMixer/1.0.0")Pretty simple stuff... I can't imagine there's anything screwy here. Then there's the plugin class, which fills in all the pure virtuals:
# include <evilcpcMixer.h>
# include <QObject>

class evilcpcMixerOSS : public QObject, public evilcpcMixer
{
Q_OBJECT
Q_INTERFACES(evilcpcMixer)
public:
evilcpcMixerOSS(QObject * parent = 0);
virtual ~evilcpcMixerOSS();

virtual const QString getName()const{return tr("OSSv3 mixer");}
virtual const QString getDescription()const{return tr("Mixer plugin utilizing the OSS v3 library");}
virtual const QString getAuthor()const{return "Richard F. Ostrow Jr.";}
virtual const bool isValid()const{return valid;}
virtual const QString errorString()const{return error;}
virtual evilcpcMixerWidget * getWidget(QWidget * parent);
virtual evilcpcPluginWidgetConfig * getConfigWidget(QWidget * parent);
virtual evilcpcPluginWidgetConfigDaemon * getConfigWidgetDaemon(QWidget * parent);
protected:
QString error;
bool valid;
evilcpcMixerWidget * w;
evilcpcPluginWidgetConfig * cw;
evilcpcPluginWidgetConfigDaemon * cwd;
};Again, pretty simple. And the implementation also contains the Q_EXPORT_PLUGIN2 line, as follows:
Q_EXPORT_PLUGIN2(LIBTARGET, evilcpcMixerOSS)LIBTARGET is defined in the end of the project file:
TEMPLATE = lib
HEADERS += evilcpcMixerOSS.h \
evilcpcMixerOSSWidget.h \
evilcpcMixerOSSWidgetConfig.h \
evilcpcMixerOSSWidgetConfigDaemon.h \
../interface/evilcpcMixer.h \
../interface/evilcpcMixerWidget.h \
../../interface/evilcpcPluginWidgetConfig.h \
../../interface/evilcpcPluginWidgetConfigDaemon.h \
../../interface/evilcpcPlugin.h
SOURCES += evilcpcMixerOSS.cpp \
evilcpcMixerOSSWidget.cpp \
evilcpcMixerOSSWidgetConfig.cpp \
evilcpcMixerOSSWidgetConfigDaemon.cpp
FORMS += formOSSMixer.ui \
formOSSMixerConfig.ui
RESOURCES += ossmixer.qrc
VERSION = 1.0.0
CONFIG += plugin debug_and_release qt resources
QT += core gui
INCLUDEPATH = ../interface ../../interface

CONFIG(debug, debug|release) {
TARGET = evilcpcMixerOSS_debug
DEFINES += LIBTARGET=evilcpcMixerOSS_debug
} else {
TARGET = evilcpcMixerOSS
DEFINES += LIBTARGET=evilcpcMixerOSS
}I went to the trouble of making sure that each interface was included in the HEADERS line of the project file, used the lib template, and added plugin to the CONFIG line. What could I possibly be missing? :crying:

fullmetalcoder
28th June 2007, 20:54
What could I possibly be missing? :crying:
So many things... :P But let's start with the most obvious one : unresolved symbols... When you build a shared library (and plugins are shared libraries) you must export some symbols... The thing, which already happened to me, is that when a method is declared but NOT defined within the plugin it can result in a "symbol lookup error" when QPluginLoader (through QLibrary actually) tries to load the plugin. This prevent the plugin instance to be created... To make sure this is not happening (or when it happens to locate the troublesome function) all you need is to create a simple test app with just a empty main() function and which LINKS to the plugin (it does not load it on run-time!!! it LINKS so you got to add the plugin to LIBS variable). This way all missing symbols should be notified when linking the test app and you'll see what to fix :)

KShots
28th June 2007, 22:16
So many things... :P But let's start with the most obvious one : unresolved symbols... When you build a shared library (and plugins are shared libraries) you must export some symbols... The thing, which already happened to me, is that when a method is declared but NOT defined within the plugin it can result in a "symbol lookup error" when QPluginLoader (through QLibrary actually) tries to load the plugin. This prevent the plugin instance to be created... To make sure this is not happening (or when it happens to locate the troublesome function) all you need is to create a simple test app with just a empty main() function and which LINKS to the plugin (it does not load it on run-time!!! it LINKS so you got to add the plugin to LIBS variable). This way all missing symbols should be notified when linking the test app and you'll see what to fix :)Wow... you were right. The problems (there were a few missing symbols) were not anywhere in those sections, but in an entirely different area... and I would never have seen it without making that simple app. Thanks!

Heh, that's the way I really prefer to get answers - teach me to fish rather than give me a fish - now I can handle this sort of problem at any time. That's incredibly valuable :).

fullmetalcoder
29th June 2007, 15:13
Wow... you were right. The problems (there were a few missing symbols) were not anywhere in those sections, but in an entirely different area... and I would never have seen it without making that simple app. Thanks!
I've been playing with plugins since about a year now and it took me a while to think about this trick so I thought it would be worth sharing it ;) Good to see that it helped you.


Heh, that's the way I really prefer to get answers - teach me to fish rather than give me a fish - now I can handle this sort of problem at any time. That's incredibly valuable :).
That's the point of a forum : sharing knowledge after having experienced several aspects of programming. We look like old soldiers sharing little tricks on how to survive on a battlefield :D