QT Plugin with CMake - qt

Greetings all,
I am trying to implement a QT Plugin with CMake. But this "Q_EXPORT_PLUGIN2" directive stops my class from compiling. I can compile the plugin if I commented this out,but it won't work as a plugin if I do so.
QT doc says:
Q_EXPORT_PLUGIN2 ( PluginName, ClassName )
The value of PluginName should
correspond to the TARGET specified in
the plugin's project file
What about in CMake case? What should be the value for 'PluginName'?
Here is my Plugin Interface :
#ifndef RZPLUGIN3DVIEWERFACTORY_H_
#define RZPLUGIN3DVIEWERFACTORY_H_
#include <QObject>
#include "plugin/IRzPluginFactory.h"
class RzPlugin3DViewerFactory :public QObject,public IRzPluginFactory{
Q_OBJECT
Q_INTERFACES(IRzPluginFactory)
private:
QString uid;
public:
RzPlugin3DViewerFactory();
virtual ~RzPlugin3DViewerFactory();
IRzPlugin* createPluginInstance();
IRzPluginContext* createPluginContextInstance();
QString & getPluginUID();
};
#endif /* RZPLUGIN3DVIEWERFACTORY_H_ */
And implementation
#include "RzPlugin3DViewerFactory.h"
#include "RzPlugin3DViewer.h"
RzPlugin3DViewerFactory::RzPlugin3DViewerFactory() {
uid.append("RzPlugin3DView");
}
RzPlugin3DViewerFactory::~RzPlugin3DViewerFactory() {
// TODO Auto-generated destructor stub
}
IRzPlugin* RzPlugin3DViewerFactory::createPluginInstance(){
RzPlugin3DViewer *p=new RzPlugin3DViewer;
return p;
}
IRzPluginContext* RzPlugin3DViewerFactory::createPluginContextInstance()
{
return NULL;
}
QString & RzPlugin3DViewerFactory::getPluginUID()
{
return uid;
}
Q_EXPORT_PLUGIN2(pnp_extrafilters, RzPlugin3DViewerFactory)
Error Message is :
[ 12%] Building CXX object
CMakeFiles/RzDL3DView.dir/RzPlugin3DViewerFactory.cpp
.obj
C:\svn\osaka3d\trunk\osaka3d\rinzo-platform\src\dlplugins\threedviewer\RzPlugin3
DViewerFactory.cpp:36: error: expected
constructor, destructor, or type
conversi on before '(' token make[2]:
*** [CMakeFiles/RzDL3DView.dir/RzPlugin3DViewerFactory.cpp.obj]
Error 1
make[1]: *
[CMakeFiles/RzDL3DView.dir/all] Error
2 make: * [all] Error 2

Ok , I fixed the problem by giving the project name specified in Cmake file.
PROJECT (RinzoDLPlugin3DViewer CXX C)
So,now in CPP file its
Q_EXPORT_PLUGIN2(RinzoDLPlugin3DViewer , RzPlugin3DViewerFactory)
and included qpluginh.h
#include <qplugin.h>

I think the macro should be Q_EXPORT_PLUGIN2(pnp_rzplugin3dviewerfactory, RzPlugin3DViewerFactory) or whatever you have listed as the target name in the .pro file. In fact, the "pnp" part stands for "Plug & Paint" which is the Qt demo program for writing plugins :)
Edit:
Since I misunderstood how CMake works, this information isn't really relevant to the OP. I did do a quick search however and turned up this discussion of Qt, plugins and CMake. I hope there is some useful info there.
http://lists.trolltech.com/qt-interest/2007-05/msg00506.html

Related

Accessing an external variable from a C library

I am currently learning C and am trying to understand the possibilities of dynamic libraries.
My current question is, if I have a simple "Hello World" application in C called "ProgA", and this program dynamically loads a shared library with some example code called "LibB", can LibB access a global variable in ProgA, which was declared as external?
Given is the following example code for demonstration of the problem:
file header.h
#ifndef TEST_H
#define TEST_H
typedef struct test_import_s {
int some_field;
} test_import_t;
extern test_import_t newtestimport;
#endif
file prog_a.c
#include <stdio.h>
#include <windows.h>
#include "header.h"
test_import_t newtestimport = {
.some_field = 42
};
int main()
{
HINSTANCE hinstLib;
typedef void (*FunctionPointer)();
newtestimport.some_field = 42;
hinstLib = LoadLibrary("lib_b.dll");
if (hinstLib != NULL)
{
FunctionPointer initialize_lib_b;
initialize_lib_b = (FunctionPointer)GetProcAddress(hinstLib, "initialize_lib_b");
if (initialize_lib_b != NULL)
{
initialize_lib_b();
}
FreeLibrary(hinstLib);
}
return 0;
}
file lib_b.c
#include <stdio.h>
#include "header.h"
test_import_t *timp;
void initialize_lib_b() {
timp = &newtestimport;
int some_field = timp->some_field;
printf("Result from function: %d\n", some_field);
}
file CMakeLists.txt
cmake_minimum_required(VERSION 3.24)
project(dynamic-library-2 C)
set(CMAKE_C_STANDARD 23)
add_library(lib_b SHARED lib_b.c)
set_target_properties(lib_b PROPERTIES PREFIX "" OUTPUT_NAME "lib_b")
add_executable(prog_a prog_a.c)
target_link_libraries(prog_a lib_b)
In the above example, the headerfile header.h defines the struct test_import_t and an external variable newtestimport using this struct. In the C file of the main program prog_a.c one property of this struct is assigned the value 42. It then dynamically loads the library lib_b.c using the Windows API and executes a function in it. The function then should access the variable newtestimport of the main program and print out the value of the variable (42).
This example does not work. The compiler throws the following error:
====================[ Build | prog_a | Debug ]==================================
C:\Users\user1\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\223.8617.54\bin\cmake\win\x64\bin\cmake.exe --build C:\Users\user1\projects\learning-c\cmake-build-debug --target prog_a -j 9
[1/2] Linking C shared library dynamic-library-2\lib_b.dll
FAILED: dynamic-library-2/lib_b.dll dynamic-library-2/liblib_b.dll.a
cmd.exe /C "cd . && C:\Users\user1\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\223.8617.54\bin\mingw\bin\gcc.exe -fPIC -g -Wl,--export-all-symbols -shared -o dynamic-library-2\lib_b.dll -Wl,--out-implib,dynamic-library-2\liblib_b.dll.a -Wl,--major-image-version,0,--minor-image-version,0 dynamic-library-2/CMakeFiles/lib_b.dir/lib_b.c.obj -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
C:\Users\user1\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\223.8617.54\bin\mingw\bin/ld.exe: dynamic-library-2/CMakeFiles/lib_b.dir/lib_b.c.obj:lib_b.c:(.rdata$.refptr.newtestimport[.refptr.newtestimport]+0x0): undefined reference to `newtestimport'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
How can the example be fixed to accomplish the described goal?
Windows DLLs are self-contained, and can not have undefined references similar to newtestimport, unless these references are satisfied by another DLL.
How can the example be fixed to accomplish the described goal?
The best fix is to pass the address of newtestimport into the function that needs it (initialize_lib_b() here).
If for some reason you can't do that, your next best option is to define the newtestimport as a dllexport variable in another DLL, e.g. lib_c.dll.
Then both the main executable and lib_b.dll would be linked against lib_c.lib, and would both use that variable from lib_c.dll.
P.S. Global variables are a "code smell" and a significant source of bugs. You should avoid them whenever possible, and in your example there doesn't seem to be any good reason to use them.

How to reference a Qt Application?

In order to test some functions of a Qt application (named qtapp), I build the Qt application as lib/dll library. The ctor and dtor have been correctly exported in the library. However compiling the test project (a Qt console project named consoleTest) is always running to the following link errors:
Link:
1> Bibliothek "C:\Users\gmbh\test\x64\Debug\consoleTest.lib" und Objekt C:\Users\gmbh\test\x64\Debug\consoleTest.exp" werden erstellt.
1>moc_testFour.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: static struct QMetaObject const qtapp::staticMetaObject" (?staticMetaObject#qtapp##2UQMetaObject##B)".
1>testFour.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: static struct QMetaObject const qtapp::staticMetaObject" (?staticMetaObject#qtapp##2UQMetaObject##B)".
1>C:\Users\gmbh\test\x64\Debug\consoleTest.exe : fatal error LNK1120: 1 nicht aufgelöste Externe
The Qt application is quite simple:
#ifndef QTAPP_H
#define QTAPP_H
#include <QtWidgets/QMainWindow>
#include "ui_qtapp.h"
class __declspec(dllexport) qtapp : public QMainWindow
{
Q_OBJECT
public:
qtapp(QWidget* parent = 0);
~qtapp();
private:
Ui::qtappClass ui;
};
#endif // QTAPP_H
Implementation:
#include "qtapp.h"
__declspec(dllexport) qtapp::qtapp(QWidget* parent)
: QMainWindow(parent)
{
ui.setupUi(this);
}
__declspec(dllexport) qtapp::~qtapp()
{
}
If I simply include #include "qtapp.h" in the test project, the compiler yields the above error.
My questions:
What are the causes for the errors?
How to correctly deploy a Qt
application as lib?
My compiler is visual studio 2013, qt has the version of 5.4.2
That's actually a question independent of Qt. When linking an application against the library you need to have __declspec(dllimport) instead of __declspec(dllexport).
To achieve that, one usually uses defines that change when linking the library vs linking the application against the library. Microsoft has a help page on that "Importing into an Application Using __declspec(dllimport)".
The Qt documentation provides another one. The one thing where Qt can help, is replacing the __declspec by a cross-platform Q_DECL_IMPORT.

Custom Qt widget example in Qt Creator errors

I'm a Qt beginner, I have the 5.2.1 version and I was trying to learn Qt/QML from a book on Github. However, this is one of the most basic examples:
#ifndef CUSTOMWIDGET_H
#define CUSTOMWIDGET_H
#include <QtWidgets>
class CustomWidget : public QWidget
{
Q_OBJECT
public:
explicit CustomWidget(QWidget *parent = 0);
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
QPoint m_lastPos;
};
#endif // CUSTOMWIDGET_H
And here are the errors I get:
ln function `_start'
undefined reference to `main'
collect2: ld returned 1 exit status
I have no idea what any of these mean, so any help would be appreciated. I made the project as a Qt Quick Application.
These are included in the .pro file
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
First you should go to google and look for the errors, you can find them and the solution, and some solutions are here in stackoverflow too.
For what I can help and hope it helps you:
ln function _start' With only that I don't know what does it mean, can you copy the full error? Maybe this can help you
undefined reference to main' Basically you are doing a example in a new project I supose so there is no main() function, which is basic for any program to run. You can add a main.cpp or declare it globaly like void main() {}Try looking at this and this
collect2: ld returned 1 exit status means that something was wrong (there are errors before this line), so that's why is the last error.

Why am I getting "undefined reference to vtable..." errors when linking this Qt 5.0 application?

I've got a relatively simple Qt 5.0 project that uses CMake 2.8.9:
CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.9)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
project(hello-world)
find_package(Qt5Widgets REQUIRED)
qt5_wrap_ui(hello-world_UI MainWindow.ui)
add_executable(hello-world MainWindow.cpp main.cpp ${hello-world_UI})
qt5_use_modules(hello-world Widgets)
MainWindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
virtual ~MainWindow();
private:
Ui::MainWindow * const ui;
};
#endif // CMAINWINDOW_H
MainWindow.cpp:
#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow::MainWindow()
: ui(new Ui::MainWindow)
{
}
MainWindow::~MainWindow()
{
delete ui;
}
main.cpp:
#include <QApplication>
#include "MainWindow.h"
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
MainWindow win;
win.show();
return app.exec();
}
The project also includes a .ui file created with Qt Creator 2.6.1 (MainWindow.ui).
When I attempt to build the file with g++ on Linux, I receive the following errors:
CMakeFiles/hello-world.dir/MainWindow.cpp.o: In function `MainWindow::MainWindow()':
MainWindow.cpp:(.text+0x3b): undefined reference to `vtable for MainWindow'
MainWindow.cpp:(.text+0x4d): undefined reference to `vtable for MainWindow'
CMakeFiles/hello-world.dir/MainWindow.cpp.o: In function `MainWindow::~MainWindow()':
MainWindow.cpp:(.text+0xaf): undefined reference to `vtable for MainWindow'
MainWindow.cpp:(.text+0xc1): undefined reference to `vtable for MainWindow'
collect2: error: ld returned 1 exit status
What could possibly be causing this sort of error? I recently switched to CMake from qmake and I never remember running into this much trouble getting a trivial example to compile. What am I doing wrong?
Edit: here is the command being used to link everything:
/usr/bin/c++ CMakeFiles/hello-world.dir/MainWindow.cpp.o
CMakeFiles/hello-world.dir/main.cpp.o -o hello-world -rdynamic
/usr/local/Qt-5.0.0/lib/libQt5Widgets.so.5.0.0
/usr/local/Qt-5.0.0/lib/libQt5Gui.so.5.0.0
/usr/local/Qt-5.0.0/lib/libQt5Core.so.5.0.0
-Wl,-rpath,/usr/local/Qt-5.0.0/lib
Turns out I forgot:
set(CMAKE_AUTOMOC ON)
At the top of the CMakeLists.txt file.
I struggled with this for a long time using all the hints published here:
http://doc.qt.io/qt-5/cmake-manual.html
And here
https://www.kdab.com/using-cmake-with-qt-5/
What I had to do was specify things in the right order. For example, the following is the top of my CMakeLists.txt. Note that the two CMAKE set directives come before add_executable. Once I did this, I was able to link without undefined symbols and vtable references. I just thought I'd post this for the benefit of others.
cmake_minimum_required (VERSION 2.8)
set (CMAKE_AUTOMOC ON)
set (CMAKE_INCLUDE_CURRENT_DIR ON)
add_executable(FHSpectrumSensor wideband_seq_spectrum_sensor.cpp sensor.cpp gui.cpp ${gui_SRC})
Later in the CMakeLists.txt I have the following:
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Charts REQUIRED)
find_package(Qt5Core REQUIRED)
qt5_use_modules(FHSpectrumSensor Widgets Charts)
qt5_wrap_cpp(gui_SRC gui.h gui.cpp)
That did the trick.
I also ran into this problem yesterday and the above mentioned answers did't help. I already used set (CMAKE_AUTOMOC ON) and also qt5_wrap_cpp.
I tried to remember what I did, because I had a working version but it stopped working after "some" changes. I finally remembered that I tried to split the include files into a separate directory hierarchy. After reverting that and putting the include files back into the CMakeLists.txt it worked again. I sure don't know why, and I would like to know what went wrong, but I settled now for keeping the includes near the cpp files.
set(SOURCES
buffer.h
ITVSet.h
MainWindow.h
MainWindow.cpp
TVSet.h
TVSet.cpp
)

Why does this Qt header file fail to get parsed by moc?

I created a new 'C++ library' project in Qt, which has the following header file:
#include "Test_global.h"
#include <QString>
#include <QTcpServer>
class TESTSHARED_EXPORT Test : QTcpServer
{
Q_OJECT
public:
Test();
~Test();
signals:
void NewMessage(QString);
};
(The implementation file is basically empty.)
When I try to build the object, I get errors:
Test.h:8: error: ISO C++ forbids declaration of ‘Q_OJECT’ with no type
Test.h:10: error: expected ‘;’ before ‘public’
Test.cpp:3: error: definition of implicitly-declared 'Test::Test()'
So it looks like moc isn't processing the file at all. What have I done wrong?
It should be Q_OBJECT, not Q_OJECT.

Resources