Unable to set library dependency in Qt - c++

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

Related

signal not correctly exported when inheriting from different dll

The following situation:
I have a class (Parent) in DLL A which has a signal (which is final). I have a class (Child) in DLL B that inherits from A. I import both DLLs to my project. Then I have a class in my project get an instance of the Child class and try to connect the signal of the Child instance to the current object. Somehow this connection fails. Running the whole thing in debug mode only gives me: QObject::connect: signal not found in Child. Checking the dumpbin shows me that the signal is in DLL A but not in DLL B. Both the class Parent and the class Child have the proper export statements but somehow the the signal for the Child class doesn't get exported. Here is the whole thing as code:
a.dll:
class DLLA_SHAREDEXPORT ParentInterface{
public:
~ParentInterface(){}
virtual void test() = 0;
};
Q_DECLARE_INTERFACE(ParentInterface, "ParentInterface")
class DLLA_SHAREDEXPORT Parent : public QObject,
public ParentInterface{
Q_OBJECT
Q_INTERFACES(ParentInterface)
...
signals:
void test();
}
b.dll:
class DLLB_SHAREDEXPORT Child : public Parent{
Q_OBJECT
...
}
class in project:
class SomeClass : public QObject{
Q_OBJECT
public:
...
void someFunction(){
Parent* c = getChildObject(); //some call to get the Object of class Child
QObject::connect(c, &Parent::test,
this, &SomeClass::handle_test);
//QObject::connect: signal not found in Child
}
}
public slots:
void handle_test(){
//do something
}
}
So the problem seems to be somewhere is the proper export of everything in the DLL B but I can't figure out how to do it. Any help would be appreciated.
I'm sorry, but I can't reproduce this issue on either Windows 10.0 with MSVC2015 and Qt 5.7 or OS X 10.10. Please try this project verbatim and see if it works for you. If it does, you're doing something else wrong and will need to produce a test case and edit it into the question.
The project is available from: https://github.com/KubaO/stackoverflown/tree/master/questions/sigslot-dll-39149263
sigslot-dll-39149263.pro
TEMPLATE = subdirs
SUBDIRS += lib1 lib2 main
main.depends += lib1 lib2
lib2.depends += lib1
lib1/lib1.pro
QT = core
CONFIG += c++11
TEMPLATE = lib
HEADERS += lib1.h
win32:DEFINES += LIB1_EXPORT=__declspec(dllexport)
lib1/lib1.h
#ifndef LIB1_H
#define LIB1_H
#include <QObject>
#ifdef WIN32
#ifndef LIB1_EXPORT
#define LIB1_EXPORT __declspec(dllimport)
#endif
#else
#define LIB1_EXPORT
#endif
class LIB1_EXPORT Parent : public QObject {
Q_OBJECT
public:
Q_SIGNAL void test();
};
#endif
lib2/lib2.pro
QT = core
CONFIG += c++11
TEMPLATE = lib
HEADERS += lib2.h
win32:DEFINES += LIB2_EXPORT=__declspec(dllexport)
win32:CONFIG(debug,release|debug) LIBSUBPATH=/debug
win32:CONFIG(release,release|debug) LIBSUBPATH=/release
LIBS += -L../lib1$$LIBSUBPATH -llib1
INCLUDEPATH += ..
DEPENDPATH += ..
lib2/lib2.h
#ifndef LIB2_H
#define LIB2_H
#include "lib1/lib1.h"
#ifdef WIN32
#ifndef LIB2_EXPORT
#define LIB2_EXPORT __declspec(dllimport)
#endif
#else
#define LIB2_EXPORT
#endif
class LIB2_EXPORT Child : public Parent {
Q_OBJECT
};
#endif
main/main.pro
QT = core
CONFIG += c++11
TEMPLATE = app
SOURCES += main.cpp
win32:CONFIG(debug,release|debug) LIBSUBPATH=/debug
win32:CONFIG(release,release|debug) LIBSUBPATH=/release
LIBS += -L../lib1$$LIBSUBPATH -llib1 -L../lib2$$LIBSUBPATH -llib2
INCLUDEPATH += ..
DEPENDPATH += ..
main/main.cpp
#include "lib1/lib1.h"
#include "lib2/lib2.h"
int main() {
int counter = 0;
Child child;
Parent * parent = &child;
QObject::connect(parent, &Parent::test, [&]{ counter++; });
emit parent->test();
emit parent->test();
Q_ASSERT(counter == 2);
}
So the issue seems to be somewhere with the usage of the Interface. We solved the issue for now by moving everything from the ParentInterface into the Parent class and removing the ParentInterface. This feels more like a workaround than a proper solution though.

QT QLibrary "Cannot load library *.so: (*.so: undefined symbol: staticMetaObject)"

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

how to create plugins (Qt 5.2.0)

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.

Qt moving slots function to another cpp file

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?

Multiply defined symbols - Linker error

I face an issue when I build and link my code with GHS multi compiler.
This is roughly the idea:
base.h -->
#ifndef base_h
#define base_h
class Base
{
void basefncn1(); // defined in src file
void basefncn2(); // defined in src file
void basefncn3(); // defined in src file
}
#endif
interface.h -->
#ifndef interface_h
#define interface_h
#include "base.h"
class Interface : public Base
{
void basefncn1();
}
#endif
derivedclass.h -->
#ifndef derived_h
#define derived_h
#include "base.h"
#include "interface.h"
class Derived : public Interface
{
void basefncn1();
}
#endif
The linker error I get is:
basefncn2() and basefncn3() is multiply defined -> Defined both in base.o and derived.o.
The header files are guarded.
Am I doing anything wrong?
Edit: I tried changing the interface.h file. The function is now defined in interface.cpp.
So basically, interface.h and derived.h does not have functions defined in it.