i ‘m trying to create a plugin(not for Qt creator),
i created an empty project and added the following files :
but i’m getting the following errors:
1.
C:\Qt\Qt5.2.0\5.2.0\mingw48_32\include\QtCore\qglobal.h:666: erreur : invalid application of ‘sizeof’ to incomplete type ‘QStaticAssertFailure’ enum {Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, COUNTER) = sizeof(QStaticAssertFailure)} ^
2.
D:\MyFiles\Projects\QtProjects\pluginTest2\plugintest.cpp:9: erreur : expected initializer before ‘PluginTest’ QString PluginTest::name() const ^
PluginTest2.pro (project name)
CONFIG += plugin
TARGET = PluginTest
CONFIG += plugin release
VERSION =1.0.0
TEMPLATE = lib
SOURCES += \
plugintest.cpp
HEADERS += \
Interface.h \
plugintest.h
interface.h
#ifndef INTERFACE_H
#define INTERFACE_H
#include <QString>
class Interface
{
public:
virtual QString name() const =0;
};
Q_DECLARE_INTERFACE(Interface,"interface /1.0.0")
#endif // INTERFACE_H
plugintest.h
#ifndef PLUGINTEST_H
#define PLUGINTEST_H
#include <QObject>
#include <QString>
#include<QtPlugin>
#include "Interface.h"
class PluginTest:public QObject,public Interface
{
Q_OBJECT
Q_INTERFACES(Interface)
public:
PluginTest();
QString name() const;
};
#endif // PLUGINTEST_H
plugintest.cpp
#include "plugintest.h"
PluginTest::PluginTest()
{
}
Q_EXPORT_PLUGIN2(PluginTest,PluginTest)
QString PluginTest::name() const
{
return "pluginTest";
}
The problem is this line:
Q_EXPORT_PLUGIN2(PluginTest,PluginTest)
This is a Qt 4 feature, so you would need to either remove it, or put behind a version checking macro as follows:
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
Q_EXPORT_PLUGIN2(PluginTest,PluginTest)
#endif
For completeness, it seems you do not specify the meta data for the plugin. You would need to add that either unconditionally or conditionally with a version checking macro if you wish to support both Qt 4 and Qt 5 as follows:
class PluginTest:public QObject,public Interface
{
Q_OBJECT
Q_INTERFACES(Interface)
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
Q_PLUGIN_METADATA(IID "your-string-here" FILE "file-here-but-can-be-empty")
#endif
...
};
Also, note that you append the "plugin" CONFIG item twice in your project file.
Related
I am working on a big project where I am trying to load dynamically a shared library with QLibrary, I was able to reproduce the run-time link error (undefined symbol: staticMetaObject) in the following example:
Folder structure:
root\
-- src\
---- TestLib\
------ TestLib.pro
------ Derived.h
------ Derived.cpp
------ TestLibModuleBridge.h
------ TestLibModuleBridge.cpp
---- TestLibCommon\
------ IBase.h
---- TestLibManager\
------ TestLibManager.pro
------ main.cpp
--lib\
TestLib files:
# TestLib.pro
QT -= gui
TARGET = TestLib
TEMPLATE = lib
QMAKE_CXXFLAGS += -Wall
DEFINES += TESTLIB_LIBRARY
SOURCES += Derived.cpp \
TestLibModuleBridge.cpp
HEADERS += Derived.h \
TestLibModuleBridge.h
INCLUDEPATH += ../TestLibCommon
unix {
target.path = ../../lib
INSTALLS += target
}
-
// Derived.h
#ifndef DERIVED_H
#define DERIVED_H
#include "IBase.h"
#include <iostream>
class Derived : public IBase
{
Q_OBJECT
public:
Derived();
virtual ~Derived();
public:
virtual void methodA();
virtual void methodB();
};
#endif // DERIVED_H
-
// Derived.cpp
#include "Derived.h"
Derived::Derived()
{
}
Derived::~Derived()
{
}
void Derived::methodA()
{
std::cout << "methodA()" << std::endl;
}
void Derived::methodB()
{
std::cout << "methodB()" << std::endl;
}
-
// TestLibModuleBridge.h
#ifndef TESTLIBMODULEBRIDGE_H
#define TESTLIBMODULEBRIDGE_H
#include "IBase.h"
#ifdef __cplusplus
extern "C" {
#endif
IBase* getModuleInterface();
#ifdef __cplusplus
}
#endif
#endif // TESTLIBMODULEBRIDGE_H
-
// TestLibModuleBridge.cpp
#include "TestLibModuleBridge.h"
#include "Derived.h"
IBase* getModuleInterface()
{
return new Derived();
}
TestLibManager Files:
// TestLibManager.pro
QT += core
QT -= gui
TARGET = TestLibManager
CONFIG += console
CONFIG -= app_bundle
QMAKE_CXXFLAGS += -Wall
TEMPLATE = app
SOURCES += main.cpp
INCLUDEPATH += ../TestLibCommon
-
// main.cpp
#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>
#include "IBase.h"
typedef IBase* (*ModuleGetterFunction) (void);
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QLibrary testLib("../../lib/libTestLib.so");
if (!testLib.load())
{
qDebug() << "Error : " << testLib.errorString();
exit(EXIT_FAILURE);
}
else
{
ModuleGetterFunction getModuleInterfaceFunc = (ModuleGetterFunction) testLib.resolve("getModuleInterface");
if (getModuleInterfaceFunc)
{
IBase* obj = getModuleInterfaceFunc();
obj->methodA();
obj->methodB();
}
}
return a.exec();
}
TestLibCommon Files
// IBase.h
#ifndef IBASE_H
#define IBASE_H
#include <QObject>
class IBase : public QObject
{
Q_OBJECT
protected:
virtual ~IBase() {}
public:
virtual void methodA() = 0;
virtual void methodB() = 0;
};
#endif // IBASE_H
The testLib.load() fails with Error : "Cannot load library ../../lib/libTestLib.so: (../../lib/libTestLib.so: undefined symbol: _ZN5IBase16staticMetaObjectE)"
How can I fix this, removing Q_OBJECT macro from IBase.h will fix the error but in the production project that interface contains signals and slots, and it is from a project we're not allowed to change.
It looks like moc has not been run before compiling the testlib.
moc is responsible for generating the staticMetaObject for classes which contain the Q_OBJECT Macro and are listed under the HEADERS section in the pro file.
Adding TestLibCommon\IBase.h to the HEADERS in TestLib.pro should probably fix this problem. (Untested).
Possible improvement of your solution:
Instead of using QLibrary take a look at QPluginLoader.
QPluginLoader will give you a QObject which you can then cast to any interface you want using qobject_cast<T*>(pluginloader.instance())
Here's an example using QPluginLoader:
http://doc.qt.io/qt-5/qtwidgets-tools-plugandpaint-example.html
In a Qt application I declare a base class:
class Base:
public QObject {
Q_OBJECT
public:
Base();
virtual ~Base();
virtual void doSomething();
};
Both the c-tor/d-tor and doSomething() have default implementations in a separate source file.
Furthermore, I provide an abstract interface to implement Qt's plugin scheme, like in the Echo Plugin Example.
class Interface {
public:
virtual ~Interface() {}
virtual Base *create() = 0;
};
#define Interface_iid "blag"
Q_DECLARE_INTERFACE(Interface, Interface_iid)
In a plugin that resides in a shared library, libPlugin.so I derive from this base class to provide custom implementations:
class Special:
public Base {
Q_OBJECT
public:
Special() { /* Implementation */ }
void doSomething() { /* Implementation */ }
};
Finally I also implement the plugin interface:
class Q_DECL_EXPORT Plugin:
public QObject,
public Interface {
Q_OBJECT
Q_PLUGIN_METADATA(IID Interface_iid)
Q_INTERFACES(Interface)
public:
Base *create() {
return new Special();
}
};
Now I can load this plugin via QPluginLoader and obtain access to its core object, which correctly identifies itself being a Plugin. But when I try to ThePlugin::create() the Special object, I get a linkage error:
symbol lookup error: libPlugin.so: undefined symbol: _ZN4BaseC2Ev
Beneath the name mangling, I suppose this refers to the Base::Base c-tor that is needed when constructing the derived Special object.
I'm tempted to compare to, e.g. a QStylePlugin: It basically does the same, returning some QStyle-derived class via an abstract interface. Please refer to the Style Plugin Example. Yet I guess the difference is that in the case of the style plugin, both the application (that provides the custom style plugin) and the style plugin itself are linked against the common Qt library that provides, e.g. the c-tors.
How could I resolve this?
What happens if link time optimization removes the c-tors because it cannot know they're needed by plugins?
Linking issue
When compiling and linking the plugin, the Base:Base() class' c-tor as well as the Base::doSomething() come out as unresolved symbol. The c-tor is called by the Special::Special() c-tor and cannot be resolved, of course. The other one is a virtual method
When compiling the application itself, it contains the implementations of the base class' methods. Obviously, they are not linked together when the plugin is loaded.
SSCCE
/********** Interface.h */
#ifndef INTERFACE_H
#define INTERFACE_H
#include <QtPlugin>
#include "Base.h"
class Interface {
public:
virtual ~Interface() { }
virtual Base *createWorker() = 0;
};
#define Interface_iid "blag"
Q_DECLARE_INTERFACE(Interface, Interface_iid)
#endif
/********** App.pro */
QT += core
TARGET = App
TEMPLATE = app
SOURCES += \
Base.cpp \
App.cpp
HEADERS += \
Base.h \
Interface.h \
/********** Base.h */
#ifndef BASE_H
#define BASE_H
#include <QObject>
class Base:
public QObject {
Q_OBJECT
public:
Base();
virtual ~Base();
virtual void doSomething();
};
#endif
/********** Base.cpp */
#include "Base.h"
Base::Base():
QObject() {
}
Base::~Base() { }
void Base::doSomething() { }
/********** App.cpp */
#include "Interface.h"
#include <QCoreApplication>
#include <QPluginLoader>
#include <QDebug>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QPluginLoader l("libPlugin.so");
qDebug() << l.load();
qDebug() << l.errorString();
return a.exec();
}
/********** Plugin.pro */
TARGET = Plugin
CONFIG += plugin
TEMPLATE = lib
SOURCES += \
Plugin.cpp \
Special.cpp \
HEADERS += \
Plugin.h \
Special.h \
Interface.h \
Base.h
/********** Special.h */
#ifndef SPECIAL_H
#define SPECIAL_H
#include <QObject>
#include "Base.h"
class Special:
public Base {
Q_OBJECT
public:
Special();
void doSomething();
};
#endif
/********** Special.cpp */
#include "Special.h"
Special::Special():
Base() {
}
void Special::doSomething() { }
/********** Plugin.h */
#ifndef PLUGIN_H
#define PLUGIN_H
#include <QObject>
#include "Interface.h"
class Q_DECL_EXPORT Plugin:
public QObject,
public Interface {
Q_OBJECT
Q_PLUGIN_METADATA(IID Interface_iid)
Q_INTERFACES(Interface)
public:
Base *createWorker();
};
#endif
/********** Plugin.cpp */
#include "Plugin.h"
#include "Special.h"
Base *Plugin::createWorker() {
return new Special();
}
Build:
# Separate files
qmake Plugin.pro && make
qmake App.pro && make
./App
I think I found what is wrong.
The construction I'd like to have linked is as follows:
A host application providing a base class with implementations
A plugin shared library that inherits from that base and re-implements some methods and/or accesses the base class' members
This basically boils down to the following in plain C:
A host application, providing some symbols
A plugin shared library, providing some more symbols and wanting to use some of the host's symbols
However, there is no generic way to achieve the latter.
A host can link against a library to use its functionality. That means the host gets method stubs that are dynamically resolved into against library once the host itself and the library are loaded. Contract between library and host may be some header file with declarations (not definitions).
When a library is dynamically loaded into a host's memory, symbols in the library in turn are not resolved against the host, though. Instead they stay unresolved.
This is exactly what I am seeing here. I tried to resolve the base class' functionality (that I did not implement in the plugin) against the host application that wants to load the plugin. Does-not-work.
This is that -rdynamic is for on ELF, refer to this post.
I have a project in Qt, with a class defined of the form
Project MyP --- file p.h
#ifndef P_H
#define P_H
#include <QImage>
class PP
{
public:
static QImage P1(const QImage& a);
}
#endif
Project MyP --- file p.cpp
#include "p.h"
QImage PP::P1(const QImage& a)
{
QImage b;
return b;
}
I created a test project for the class above
project test, file test.h
#ifndef TEST_H
#define TEST_H
#include <QtTest/QtTest>
class Test : public QObject
{
Q_OBJECT
private slots:
void TestSomething();
};
#endif
#include "test.h"
#include "p.h"
void Test::TestSomething()
{
QImage sourceImage = QImage("source.png");
QImage newImage = PP::P1(sourceImage);
int result = 1*2;
QVERIFY(result == 2);
}
QTEST_MAIN(Test)
doing the same thing in c++ works but there I can easily add a lib dependency)... but in Qt i get an error
error: undefined reference to `_imp___ZN6PPP1ENS_12P1MethodERK6QImage'
I tried to add library dependency like i saw here
http://qt-project.org/wiki/How_to_create_a_library_with_Qt_and_use_it_in_an_application
I added in the MyP header file
#if defined MYP_LIB
#define MYP_COMMON_DLLSPEC Q_DECL_EXPORT
#else
#define MYP_COMMON_DLLSPEC Q_DECL_IMPORT
#endif
and changed the class declaration to
class MYP_COMMON_DLLSPEC Dither
{
....
}
I added in the pro file ( I will post the entire file for ease)
TEMPLATE = lib
VERSION = 1.0.0.0
CONFIG += staticlib debug
debug {
DESTDIR = bin/debug
}
release {
DESTDIR = bin/release
}
HEADERS += \
pp.h
SOURCES += \
pp.cpp
DEFINES += MYP_LIB
then in the test project, I added in the pro file
DEPENDPATH += . ../myp
INCLUDEPATH += ../myp
win32:LIBS += ../myp/bin/debug/libmyp.a
LIBS+= -L../myp/bin/debug -lmyp
I have been unable to create a lib file, or a dll file, and have been unable to get the projects to work together. Note: they are all in the same solution.
How can I properly run the test from a separate project ?
You have to tell the linker to import and export (respectively) a symbol from or to a DLL, so you have to declare your class like:
Project MyP --- file p.h
#ifndef P_H
#define P_H
#if defined(MyP_LIBRARY)
# define MyPSHARED_EXPORT Q_DECL_EXPORT
#else
# define MyPSHARED_EXPORT Q_DECL_IMPORT
#endif
#include <QImage>
MyPSHARED_EXPORT class PP
{
public:
...
And add
DEFINES += MyP_LIBRARY
to your MyP.pro file
more information at
http://qt-project.org/doc/qt-4.8/sharedlibrary.html
I have a Qt project made by Qt creator.
I let the creator itself generate a private slots function fx. on_pushbutton_clicked().
This function is declared in header, the function itself is in the cpp file created by the Qt creator.
When I move the function from cpp file generated by Qt creator to another cpp file (it is added in the project, it has the same includes as the generated cpp.
When I try to compile it, I get lnk2019 error.
Is there any way to have slots functions in different files?
I am using VC compiler.
Okay, here is extract from the code. (it is quite long)
gui.h
#ifndef GUI_H
#define GUI_H
#include <QMainWindow>
#include "buffer.h"
#include <string>
#include <map>
#include <math.h>
#include <sstream>
#include <stdlib.h>
#include "qcustomplot.h"
#include <limits>
#include <time.h>
#include <random>
namespace Ui {
class GUI;
}
class GUI : public QMainWindow
{
Q_OBJECT
public:
explicit GUI(QWidget *parent = 0);
~GUI();
private slots:
void on_setall_clicked();
void on_integrace_button_clicked();
void on_elipsy_button_clicked();
void on_grafy_button_clicked();
private:
Ui::GUI *ui;
};
#endif // GUI_H
gui.cpp
#include "gui.h"
#include "ui_gui.h"
double drand(double from, double to){
double f = (double)rand()/RAND_MAX;
return from + f * (to - from);
}
GUI::GUI(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::GUI)
{
ui->setupUi(this);
srand(time(0));
}
GUI::~GUI()
{
delete ui;
}
void GUI::on_setall_clicked(){...};
void GUI::on_grafy_button_clicked(){...};
void GUI::on_integrace_button_clicked(){...};
elipsy.cpp
#include "gui.h"
void GUI::on_elipsy_button_clicked(){...};
GUI.pro
#-------------------------------------------------
#
# Project created by QtCreator 2013-03-27T09:01:31
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
TARGET = GUI
TEMPLATE = app
SOURCES += main.cpp\
gui.cpp \
solve_rpn.cpp \
shunting_yard.cpp \
qcustomplot.cpp \
elipsy.cpp \
grafy.cpp \
integrace.cpp
HEADERS += gui.h \
buffer.h \
qcustomplot.h
FORMS += gui.ui
And the error code it gives me when i try to compile with the function elipsy_button_clicked() in file other than gui.cpp
moc_gui.obj:-1: Chyba:LNK2019: unresolved external symbol "private: void __cdecl GUI::on_elipsy_button_clicked(void)" (?on_elipsy_button_clicked#GUI##AEAAXXZ) referenced in function "private: static void __cdecl GUI::qt_static_metacall(class QObject *,enum QMetaObject::Call,int,void * *)" (?qt_static_metacall#GUI##CAXPEAVQObject##W4Call#QMetaObject##HPEAPEAX#Z)
debug\GUI.exe:-1: Chyba:LNK1120: 1 unresolved externals
Well, in case you need the entire sourcecode, I uploaded it
http://seed.gweana.eu/public/GUI.7z
FIXED: The file was ignored by the project, running qmake again solved the issue. Many thanks for the answers :)
One of the problems is that you exported the slot methods to elipsy.cpp where on line 14 you try to use: ui ... which is defined in ui_gui.h included only in gui.cpp, but forward declared in gui.h (which you include of course in elipsy.cpp) so this should give you a compilation error. Solution: include ui_gui.h in elipsy.cpp. If it doesn't give you a compilation error try to rebuild the application.
Secondly, your drand function is defined in gui.cpp but not in any header file (easily fixable, modify gui.h)...
After fixing these two issues the compilation was ok for me.
So, a few recommendations:
Leave the things as they are when comes to Qt ... you will just mess up your head when moving things around.
have a separate "module" for utilities, such as drand
(PS: Nice app :) )
Generally slots are declared in a header file like,in my Counter.h :
#include <QObject>
class Counter : public QObject
{
Q_OBJECT
public:
Counter() { m_value = 0; }
int value() const { return m_value; }
public slots:
void setValue(int value);
....
Now in Counter.cpp(and it has to include Counter.h), i will define this function like any other normal function.
So in this case everything will work correctly.Does that answers your question?
I'm having a very serious issue with QT Creator. I can no longer use pointers to other classes and autocompletion doesn't work in my primary class. It feels like something has become corrupt, but all my code was working with a few pointers existing, then all at once none of them worked and errored out.
Line 21: InkPuppet *pointerToPuppet; errors: x:\development\inkpuppet\newdialog.h:21: error: C2143: syntax error : missing ';' before '*' and x:\development\inkpuppet\newdialog.h:21: error: C4430: missing type specifier - int assumed. Note: C++ does not support default-int
Here is my .pro file:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = InkPuppet
TEMPLATE = app
SOURCES += main.cpp\
inkpuppet.cpp \
aboutdialog.cpp \
inkspot.cpp \
newdialog.cpp
HEADERS += inkpuppet.h \
aboutdialog.h \
inkspot.h \
newdialog.h
FORMS += inkpuppet.ui \
aboutdialog.ui \
newdialog.ui
OTHER_FILES += \
InkPuppet.pro.user
RESOURCES += \
resources.qrc
Here is my default header. inkpuppet.h
#ifndef INKPUPPET_H
#define INKPUPPET_H
#include "inkspot.h"
#include "ui_inkpuppet.h"
#include <QMainWindow>
#include <QWidget>
namespace Ui {
class InkPuppet;
}
class InkPuppet : public QMainWindow
{
Q_OBJECT
public:
explicit InkPuppet(QWidget *parent = 0);
~InkPuppet();
Ui::InkPuppet *ui;
private slots:
void setMinimum(int value);
void setMaximum(int value);
void actionNew();
void actionAbout();
void testButton();
};
#endif // INKPUPPET_H
newdialog.h
#ifndef NEWDIALOG_H
#define NEWDIALOG_H
#include "inkspot.h"
#include "inkpuppet.h"
#include "ui_inkpuppet.h"
#include <QDialog>
namespace Ui {
class NewDialog;
}
class NewDialog : public QDialog
{
Q_OBJECT
public:
explicit NewDialog(QWidget *parent = 0);
~NewDialog();
InkPuppet *pointerToPuppet;
private:
Ui::NewDialog *ui;
private slots:
void createNew();
};
#endif // NEWDIALOG_H
Replace "InkPuppet *pointerToPuppet;" with "Ui::InkPuppet *pointerToPuppet;" will fix your compilation issue.
Reinstalling yourSDK may solve auto-completion issue. Problem with Qt creator autocomplete code