Results 1 to 5 of 5

Thread: Getting Qt to recognize plugins...

  1. #1
    Join Date
    Feb 2006
    Location
    USA
    Posts
    142
    Thanks
    24
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Default Getting Qt to recognize plugins...

    Hello all,

    I've been following the docs for developing a plugin for my Qt application, using the low-level approach, as well as the plug & paint example. For whatever reason, when I run my application, it detects the plugin files but cannot generate an instance from them. Here's what I've got (using a single plugin as an example, and the relevant sections of my application).

    First, I'll start with my interface, input.h:
    Qt Code:
    1. #ifndef INPUT_H
    2. #define INPUT_H
    3.  
    4. # include <QObject>
    5.  
    6. class QPoint;
    7.  
    8. class input
    9. {
    10. Q_OBJECT
    11. public:
    12. input() : allow(true){}
    13. virtual ~input(){}
    14.  
    15. virtual const QString getName()const = 0;
    16. virtual const QString getDescription()const = 0;
    17. public slots:
    18. virtual void setAllow(bool allow) = 0;
    19. signals:
    20. void menuUp();
    21. void menuDown();
    22. void menuLeft();
    23. void menuRight();
    24. void tap(const QPoint & p);
    25. protected:
    26. bool allow;
    27. };
    28.  
    29. Q_DECLARE_INTERFACE(input,
    30. "com.warfaresdl.evilcpc.input/1.0.0")
    31.  
    32. #endif
    To copy to clipboard, switch view to plain text mode 
    And below, a sample input plugin, inputvoice.h:
    Qt Code:
    1. #ifndef INPUTVOICE_H
    2. #define INPUTVOICE_H
    3.  
    4. # include <input.h>
    5.  
    6. class inputVoice : public input, public QObject
    7. {
    8. Q_OBJECT
    9. Q_INTERFACES(input)
    10. public:
    11. inputVoice(QObject * p = 0);
    12. virtual ~inputVoice();
    13.  
    14. virtual const QString getName()const;
    15. virtual const QString getDescription()const;
    16. public slots:
    17. virtual void setAllow(const bool allow);
    18. };
    19.  
    20. #endif
    To copy to clipboard, switch view to plain text mode 
    ... and its implementation, inputVoice.cpp:
    Qt Code:
    1. #include "inputVoice.h"
    2. #include <QtPlugin>
    3.  
    4. inputVoice::inputVoice(QObject * p) : input(), QObject(p)
    5. {
    6. }
    7.  
    8. inputVoice::~inputVoice()
    9. {
    10. }
    11.  
    12. const QString inputVoice::getName()const
    13. {
    14. return tr("Voice");
    15. }
    16.  
    17. const QString inputVoice::getDescription()const
    18. {
    19. return tr("Voice input plugin");
    20. }
    21.  
    22. void inputVoice::setAllow(const bool a)
    23. {
    24. allow = a;
    25. }
    26.  
    27. Q_EXPORT_PLUGIN2(inputVoice, inputVoice)
    To copy to clipboard, switch view to plain text mode 
    The qmake .pro file for this plugin (voice):
    Qt Code:
    1. TEMPLATE = lib
    2. HEADERS = inputVoice.h
    3. SOURCES = inputVoice.cpp
    4. VERSION = 1.0.0
    5. CONFIG = plugin debug_and_release qt
    6. QT = core
    7. INCLUDEPATH = ../interface
    8.  
    9. CONFIG(debug, debug|release) {
    10. TARGET = inputVoice_debug
    11. } else {
    12. TARGET = inputVoice
    13. }
    To copy to clipboard, switch view to plain text mode 
    This generates a file, libinputVoice.so, which I sym-link to my application's project directory under a "plugins" sub-folder. My application uses the following qmake project file:
    Qt Code:
    1. CONFIG = debug_and_release qt warn_on thread
    2. QT = core
    3. TEMPLATE = app
    4. HEADERS =
    5. SOURCES = main.cpp
    6. INCLUDEPATH = ../plugins/menu/interface \
    7. ../plugins/menuItem/interface \
    8. ../plugins/input/interface
    9. LIBS += -lmenu \
    10. -lpanel \
    11. -lncurses
    12.  
    13. CONFIG(debug, debug|release) {
    14. TARGET = evilcpcconf-debug
    15. } else {
    16. TARGET = evilcpcconf
    17. }
    To copy to clipboard, switch view to plain text mode 
    ... and in my application code, I use the following to load the plugin (stderr has been redirected to error.log via freopen):
    Qt Code:
    1. unsigned int index;
    2. //load plugins at this point...
    3. QStringList lPluginName;
    4. QStringList lPluginDescription;
    5. QStringList lPluginFile;
    6. QDir pluginsDir = QDir(QCoreApplication::applicationDirPath());
    7. #if defined(Q_OS_WIN)
    8. if(pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
    9. {
    10. pluginsDir.cdUp();
    11. }
    12. #elif defined(Q_OS_MAC)
    13. if(pluginsDir.dirName() == "MacOS")
    14. {
    15. pluginsDir.cdUp();
    16. pluginsDir.cdUp();
    17. pluginsDir.cdUp();
    18. }
    19. #endif
    20. cerr << "Using plugin path: " << pluginsDir.absolutePath().toAscii().data() << endl;
    21. pluginsDir.cd("plugins");
    22. cerr << "Changed to: " << pluginsDir.absolutePath().toAscii().data() << endl;
    23. foreach(QString fileName, pluginsDir.entryList(QDir::Files))
    24. {
    25. cerr << "Found a file: " << pluginsDir.absoluteFilePath(fileName).toAscii().data() << endl;
    26. QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
    27. QObject * plugin = loader.instance();
    28. if(!plugin)
    29. { // This is where each plugin is ending up
    30. cerr << fileName.toAscii().data() << " is not a valid plugin..." << endl;
    31. }
    32. else
    33. {
    34. cerr << fileName.toAscii().data() << " is a valid plugin" << endl;
    35. if(qobject_cast<input *>(plugin))
    36. {
    37. cerr << fileName.toAscii().data() << " is an input plugin" << endl;
    38. input * i = qobject_cast<input *>(plugin);
    39. lPluginFile << fileName;
    40. lPluginName << i->getName();
    41. lPluginDescription << i->getDescription();
    42. }
    43. }
    44. }
    45. if(!lPluginName.size())
    46. {
    47. return;
    48. }
    To copy to clipboard, switch view to plain text mode 
    ... and the cerr output:
    Qt Code:
    1. Using plugin path: /home/rich/svn/evilcpc/trunk/evilcpcconf
    2. Changed to: /home/rich/svn/evilcpc/trunk/evilcpcconf/plugins
    3. Found a file: /home/rich/svn/evilcpc/trunk/evilcpcconf/plugins/libinputVoice.so
    4. libinputVoice.so is not a valid plugin...
    5. Found a file: /home/rich/svn/evilcpc/trunk/evilcpcconf/plugins/libmenuAeon.so
    6. libmenuAeon.so is not a valid plugin...
    7. Found a file: /home/rich/svn/evilcpc/trunk/evilcpcconf/plugins/libmenuBasic.so
    8. libmenuBasic.so is not a valid plugin...
    9. Found a file: /home/rich/svn/evilcpc/trunk/evilcpcconf/plugins/libmenuItemGps.so
    10. libmenuItemGps.so is not a valid plugin...
    To copy to clipboard, switch view to plain text mode 
    What am I doing incorrectly in my plugin code?
    Life without passion is death in disguise

  2. #2
    Join Date
    Feb 2006
    Location
    USA
    Posts
    142
    Thanks
    24
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: Getting Qt to recognize plugins...

    Ok, I think I found the problem. The issue is that the docs don't explain very well what needs to go into the qmake project file, and that it also claims that the interface should not inherit from QObject.

    Including the interface in my project file for my plugin cause Qt to actually care about the content of input.h... which then told me that because I used the Q_OBJECT macro, I need to inherit from QObject. Once that was done, the plugin was recognized. Here's the changes I needed to make.

    The plugin project file:
    Qt Code:
    1. TEMPLATE = lib
    2. HEADERS = inputVoice.h \
    3. ../interface/input.h <--------Added this line
    4. SOURCES = inputVoice.cpp
    5. VERSION = 1.0.0
    6. CONFIG = plugin debug_and_release qt
    7. QT = core
    8. INCLUDEPATH = ../interface
    9.  
    10. CONFIG(debug, debug|release) {
    11. TARGET = inputVoice_debug
    12. } else {
    13. TARGET = inputVoice
    14. }
    To copy to clipboard, switch view to plain text mode 
    The interface header:
    Qt Code:
    1. #ifndef INPUT_H
    2. #define INPUT_H
    3.  
    4. # include <QObject>
    5.  
    6. class QPoint;
    7.  
    8. class input : public QObject // <----- This line changed
    9. {
    10. Q_OBJECT
    11. public:
    12. input(QObject * p = 0) : QObject(p), allow(true){} // <----- This line changed
    13. virtual ~input(){}
    14.  
    15. virtual const QString getName()const = 0;
    16. virtual const QString getDescription()const = 0;
    17. public slots:
    18. virtual void setAllow(bool allow) = 0;
    19. signals:
    20. void menuUp();
    21. void menuDown();
    22. void menuLeft();
    23. void menuRight();
    24. void tap(const QPoint & p);
    25. protected:
    26. bool allow;
    27. };
    28.  
    29. Q_DECLARE_INTERFACE(input,
    30. "com.warfaresdl.evilcpc.input/1.0.0")
    31.  
    32. #endif
    To copy to clipboard, switch view to plain text mode 
    The plugin header:
    Qt Code:
    1. #ifndef INPUTVOICE_H
    2. #define INPUTVOICE_H
    3.  
    4. # include <input.h>
    5.  
    6. class inputVoice : public input // <----- This line changed (don't inherit QObject here)
    7. {
    8. Q_OBJECT
    9. Q_INTERFACES(input)
    10. public:
    11. inputVoice(QObject * p = 0);
    12. virtual ~inputVoice();
    13.  
    14. virtual const QString getName()const;
    15. virtual const QString getDescription()const;
    16. public slots:
    17. virtual void setAllow(const bool allow);
    18. };
    19.  
    20. #endif
    To copy to clipboard, switch view to plain text mode 
    ... and finally the plugin implementation:
    Qt Code:
    1. #include "inputVoice.h"
    2. #include <QtPlugin>
    3.  
    4. inputVoice::inputVoice(QObject * p) : input(p) // <-----This line changed
    5. {
    6. }
    7.  
    8. inputVoice::~inputVoice()
    9. {
    10. }
    11.  
    12. const QString inputVoice::getName()const
    13. {
    14. return tr("Voice");
    15. }
    16.  
    17. const QString inputVoice::getDescription()const
    18. {
    19. return tr("Voice input plugin");
    20. }
    21.  
    22. void inputVoice::setAllow(const bool a)
    23. {
    24. allow = a;
    25. }
    26.  
    27. Q_EXPORT_PLUGIN2(inputVoice, inputVoice)
    To copy to clipboard, switch view to plain text mode 
    Life without passion is death in disguise

  3. #3
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Getting Qt to recognize plugins...

    If you want to use plugins through QPluginLoader, as the docs state, you must respect some basic rules (apart from the Q_DECLARE_INTERFACE and Q_EXPORT_PLUGIN2 macros stuff) :

    1. Your interface MUST be an interface, i.e an abstract class with only pure virtual methods and a virtual destructor defined in the header
    2. The first rule implies a second one : no inheritance from non-abstract classes
    3. The second rule implies that plugin interfaces can't make use of the meta object system, i.e. no signals, no slots no events, ... (note : this does not mean that implementations can't...)
    4. as with every QObject classes, the implementation of an interface must place QObject first in its inheritance chain and multiple inheritance from QObject is impossible due to the way the meta object system works internally
    5. All the methods declared by your plugin implementation MUST be implemented, even those not declared in the interface, otherwise a "symbol lookup error" is likely to happen which will prevent the loading of your plugin

    Alternatively, if these rules are not compatible with what you want to achieve you might consider writing your own plugin loading code. This is not real hard : all you need is to use QLibrary and to create an extra function in your plugins which create an instance of your object (just like Qt plugin loading is done with QPluginLoader...). Additionnaly, if the inheritance limit is especially important you'll have to split your code in at list an executable and one library which would contain the implementation of plugin interfaces (thus allowing the use of meta object system and other similar niceties but bringing some architectural difficulties and extra run-time tricks under Nix )

    Hope this helps.
    Current Qt projects : QCodeEdit, RotiDeCode

  4. #4
    Join Date
    Feb 2006
    Location
    USA
    Posts
    142
    Thanks
    24
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: Getting Qt to recognize plugins...

    Hmm... I was able to successfully compile and link to my plugin when my interface inheritted from QObject, and had a default constructor and a variable. I was able to access both of my functions that way.

    However, I think I see what you're saying as well... if I want my plugin to do something beyond simple QObject stuff (like QWidget or similar), I may have to find another solution. Also, as I'm bending the rules you listed above a bit, I'm not sure how much further I could get away with what I'm doing anyways.
    Life without passion is death in disguise

  5. #5
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Getting Qt to recognize plugins...

    Quote Originally Posted by KShots View Post
    Hmm... I was able to successfully compile and link to my plugin when my interface inheritted from QObject, and had a default constructor and a variable. I was able to access both of my functions that way.
    Well, I might have made a mistake... Actually it seems that you can inherit your interface from any Qt class BUT you shouldn't anyway be able to access, for instance, your custom signals, or any other method that is IMPLEMENTED in the base class... Does your plugin implementation successfully emit signals defined in the base class???
    Current Qt projects : QCodeEdit, RotiDeCode

Similar Threads

  1. Nightmares with plugins
    By KShots in forum Qt Programming
    Replies: 6
    Last Post: 8th February 2007, 16:46
  2. Qt plugins - how to do a libtool-style autoload
    By KShots in forum Qt Programming
    Replies: 2
    Last Post: 7th February 2007, 12:40
  3. Arthur Plugins demos and designer
    By antonio.r.tome in forum Installation and Deployment
    Replies: 4
    Last Post: 21st March 2006, 14:01
  4. How to reload widget plugins?
    By victorng in forum Qt Programming
    Replies: 2
    Last Post: 1st March 2006, 23:27
  5. Plugins as small application
    By blackliteon in forum Qt Programming
    Replies: 4
    Last Post: 12th January 2006, 09:39

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.