cmake qt6: unresolved external symbol “public: virtual struct QMetaObject” - qt

I am building qt6 project with cmake. I want to generate a library with QWidget, and the code is:
#ifndef GLOBAL_EXPORTS
#define GLOBAL_EXPORT __declspec(dllexport)
#else
#define GLOBAL_EXPORT __declspec(dllimport)
#endif // !GLOBAL_EXPORTS
class GLOBAL_EXPORT SWidgets : public QWidget
{
Q_OBJECT
public:
SWidgets();
};
In compiling, the vs reports:
unresolved external symbol "public: virtual struct QMetaObject const SWidgets::staticMetaObject"
The bug can be solved by copy moc file. But, it is inconvenient because I have many qt relative library.
In addition, I have add set(CMAKE_AUTOMOC 1), and it do not work.
I have upload the code in github (https://github.com/zhang-qiang-github/cmake_qt).
How to solve this bug by cmake? Any suggestion is appreciated~~~
Update: sorry for uploading code to github.
First, I define my GLOBAL_EXPORTS in a Global.h file:
#ifndef GLOBAL_EXPORTS_H
#define GLOBAL_EXPORTS_H
#if (WIN32)
#ifndef GLOBAL_EXPORTS
#define GLOBAL_EXPORT __declspec(dllexport)
#else
#define GLOBAL_EXPORT __declspec(dllimport)
#endif // !GLOBAL_EXPORTS
#else
#define GLOBAL_EXPORT
#endif
#endif
Then I define my custom widget as:
#ifndef swidget_header_h
#define swidget_header_h
#include "Global.h"
#include <qwidget.h>
#include "qpushbutton.h"
class GLOBAL_EXPORT SWidgets : public QWidget
{
Q_OBJECT
public:
SWidgets();
};
#endif // !swidget_header_h

As #Tsyvarev has pointed out, your handling of the GLOBAL_EXPORTS definition is wrong.
You should export the symbols if the GLOBAL_EXPORTS definition is set, therefore it should read (note: I changed #ifndef to #ifdef):
#ifdef GLOBAL_EXPORTS
#define GLOBAL_EXPORT __declspec(dllexport)
#else
#define GLOBAL_EXPORT __declspec(dllimport)
#endif // !GLOBAL_EXPORTS
Then in your CMakeLists.txt of the export_dll project you should add a line defining GLOBAL_EXPORTS:
set(CMAKE_AUTOMOC 1)
add_library(export_dll SHARED ${SOURCES} ${HEADERS})
set_target_properties(export_dll PROPERTIES COMPILE_DEFINITIONS GLOBAL_EXPORTS)
find_package(Qt6 REQUIRED COMPONENTS Widgets Core Gui)
target_link_libraries(export_dll PRIVATE Qt6::Widgets Qt6::Core Qt6::Gui)
By doing this __declspec(dllexport) will be added to the symbols when creating the DLL and every consumer of the DLL will automatically get the symbols with a proper __declspec(dllimport) set.

Related

QT VS Tools how to use qt static class library correctly

I am trying to work on qt class libraries and I want to include a qt class library in a qt application.
Platform is visual studio 2022, Qt tools and Qt 6.4.1.
Application and class library I created via project wizard.
I have included the class library via "Verweise" and added the path to the header and library path in the QT project settings.
VS Project:
QT project settings
Testlib.h
#pragma once
#include "testlib_global.h"
class TESTLIB_EXPORT TestLib
{
public:
TestLib();
void SayHello();
};
Testlib_global.h
#pragma once
#include <QtCore/qglobal.h>
#ifndef BUILD_STATIC
# if defined(TESTLIB_LIB)
# define TESTLIB_EXPORT Q_DECL_EXPORT
# else
# define TESTLIB_EXPORT Q_DECL_IMPORT
# endif
#else
# define TESTLIB_EXPORT
#endif
Testlib.cpp
#include "TestLib.h"
TestLib::TestLib()
{
}
void TestLib::SayHello()
{
}
Main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtCore/qglobal.h>
#include "testlib.h"
int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
TestLib* lib = new TestLib();
lib->SayHello();
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
After compiling I get the following errors
Severity Code Description Project File Line Suppression State
Error LNK2019 Reference to unresolved external symbol ""__declspec(dllimport) public: __cdecl TestLib::TestLib(void)" (__imp_??0TestLib##QEAA#XZ)" in function "main". TestApp C:\Users\arne\workspace4\TestApp\main.obj 1
Severity Code Description Project File Line Suppression state
Error LNK2019 Reference to unresolved external symbol ""__declspec(dllimport) public: void __cdecl TestLib::sayHello(void)" (__imp_?sayHello#TestLib##QEAAXXZ)" in function "main". TestApp C:\Users\arne\workspace4\TestApp\main.obj 1
Two unresolved external
Probably this is a beginner's problem - I'm just switching from c# to c++ due to the project and it's much more complex.
Since the application itself is already very complex i wanted to at least create the structures correctly right at the beginning and for that i need several libraries
Thanks for any support
Testlib project settings

Qt: Compare QVariable with Enum of DLL

I try to compare a QVariable of a QSignalSpy with a Enum in a test function. I found Q_ENUM_NS, but I got a linker error. I have rebuilt it and run qmake.
Error Message: Undefined reference to CCS::staticMetaObject
testopcua.cpp (most parts)
Q_DECLARE_METATYPE(CCS::DataManagerState)
using namespace ::testing;
class TestOpcUa : public Test
{
public:
TestOpcUa()
{
//.....
}
~TestOpcUa()
{
delete _selectedConfValid;
delete _opcUaObjectValid;
}
protected:
MockOpcConf* _selectedConfValid = nullptr;
OpcUa* _opcUaObjectValid = nullptr;
};
TEST_F(TestOpcUa, checkHandshake)
{
qRegisterMetaType<CCS::DataManagerState>("state");
QSignalSpy readySpy(_opcUaObjectValid, SIGNAL(newManagerState(CCS::DataManagerState)));
_opcUaObjectValid->connect();
readySpy.wait();
ASSERT_EQ(readySpy.count(), 1);
ASSERT_EQ(readySpy.at(0).at(0).value<CCS::DataManagerState>(), CCS::DataManagerState::Ready); //Linker error
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
enums.h of DLL
#include <QObject>
namespace CCS
{
Q_NAMESPACE
enum class DataManagerState
{None, Configure, Ready, Active, Waiting, Stop};
Q_ENUM_NS(DataManagerState)
}
I think you need to add an explicit export/import directive to the QT_NAMESPACE macro.
namespace CCS
{
Q_DECL_EXPORT Q_NAMESPACE
...
}
But you'll most likely need to abstract the Q_DECL_EXPORT part so it is a Q_DECL_IMPORT in right circumstances, as described in Creating Shared Libraries (or in the Qt Wiki How to create a library with Qt...)
global.h of DLL
#include <QtCore/QtGlobal>
#if defined(MYSHAREDLIB_LIBRARY)
# define MYSHAREDLIB_EXPORT Q_DECL_EXPORT
#else
# define MYSHAREDLIB_EXPORT Q_DECL_IMPORT
#endif
enums.h of DLL
#include "global.h"
#include <QObject>
namespace CCS
{
MYSHAREDLIB_EXPORT Q_NAMESPACE
...
}
Note that if you plan to also use the "DLL" code as a statically linked lib (or directly included in other code, w/out any lib), you'll need a 3rd condition in global.h which defines MYSHAREDLIB_EXPORT as nothing.
global.h of DLL
#include <QtCore/QtGlobal>
#if defined(MYSHAREDLIB_LIBRARY)
# define MYSHAREDLIB_EXPORT Q_DECL_EXPORT
#elif defined(MYSHAREDLIB_STATIC)
# define MYSHAREDLIB_EXPORT
#else
# define MYSHAREDLIB_EXPORT Q_DECL_IMPORT
#endif
Q_DECLARE_METATYPE(CCS::DataManagerState)
Shouldn't need this.
Since Qt 5.14 you can use Q_NAMESPACE_EXPORT macro.
https://doc.qt.io/qt-5/qobject.html#Q_NAMESPACE_EXPORT
namespace CSS
{
Q_NAMESPACE_EXPORT(MYSHAREDLIB_LIBRARY)
...
}

Qt QOpenGLFunctions not declared in this scope

I'm creating a sort of drawable object class for mesh data and i'm getting this linker error. This is also on top of another class that handles the drawing of the meshes that was used in one of the Qt tutorials. I'm also using a QGLWidget to be the surface i'm drawing to. Here's what the header file looks for the first class.
#ifndef GLOBJECT_H
#define GLOBJECT_H
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QVector3D>
#include <QVector2D>
#include <QDebug>
#include <QFile>
struct VertexData
{
QVector3D position;
QVector2D texCoord;
QVector3D normal;
};
class GLObject
{
public:
GLObject();
VertexData *data;
GLushort *indices;
GLuint vboIds[2];
int faceCount, vertCount;
bool generateFromPLY(QString filename);
};
#endif // GLOBJECT_H
Here's the header for the other class.
#ifndef GEOMETRYENGINE_H
#define GEOMETRYENGINE_H
#include <QObject>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QVector2D>
#include <QVector3D>
#include <QFile>
#include <QDebug>
#include <QVector>
#include <globject.h>
class GeometryEngine : public QObject, protected QOpenGLFunctions
{
Q_OBJECT
public:
GeometryEngine();
~GeometryEngine();
void init();
void drawGeometry(QOpenGLShaderProgram *program);
//void drawCubeGeometry(QOpenGLShaderProgram *program);
bool generateFromPly(QString filename);
QVector<GLObject> drawables;
int drawableId = 0;
};
#endif // GEOMETRYENGINE_H
G:\Dropbox\GLSLDemo\globject.cpp:60: error: 'glGenBuffers' was not declared in this scope
glGenBuffers(2, vboIds);
along with the same error for the other gl calls.
Initially I had all the code in GeometryEngine to begin with. I didn't have a scope issue then. initilizeOpenGLFunctions() is called in GeometryEngine's init() if that's relevant.
^
QT OpenGL is weird. I think the QOpenGLFunctions maintains a common context. Also i'm bad at C++ and used protected wrong.

templated class in Qt

Is it possible to use a templated class (not based on QObject and doesn't have Q_OBJECT macro) in Qt? I keep getting a linker error when trying to use a templated class. however, when I remove the template from the class, it compiles and links fine. I'm just trying to declare a local variable of type Filter, which uses a template, and I get this linker error:
error: undefined reference to `NumericFilter<int>::NumericFilter(int, int)'
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "filter.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
NumericFilter<int> filter(0, 1);
}
MainWindow::~MainWindow()
{
delete ui;
}
filter.h
template <class T>
class NumericFilter {
public:
NumericFilter (int itemType, int val);
protected:
T m_val;
};
filter.cpp
#include "filter.h"
template <class T>
NumericFilter<T>::NumericFilter (int, int)
{
}
Note that if you remove the template in the declaration and source files and comment out the 'T' member, then it compiles fine.
http://www.parashift.com/c++-faq-lite/separate-template-fn-defn-from-decl.html
If you compile and (try to) link these two .cpp files, most compilers will generate linker errors. There are two solutions for this. The first solution is to physically move the definition of the template function into the .h file, even if it is not an inline function.
This solution may (or may not!) cause significant code bloat, meaning your executable size may increase dramatically (or, if your compiler is smart enough, may not; try it and see).
The other solution is to leave the definition of the template function in the .cpp file and simply add the line template void foo(); to that file:
// File "foo.cpp"
#include <iostream>
#include "foo.h"
template<typename T> void foo()
{
std::cout << "Here I am!\n";
}
template void foo<int>();
So for your case, you would have in your .cpp file:
#include "filter.h"
template <class T>
NumericFilter<T>::NumericFilter(int, int)
{
}
template NumericFilter<int>::NumericFilter<int>(int, int); // added line!!!
Tada! No compile errors!
BTW, parashift's explanations on templates in C++ are the best IMHO.
Hope that helps.

Export QObject-based class to DLL

I'm composing a class which derives from QObject, and I want to export this class into a DLL file so other applications can use it. But I got some mysterious problem here:
The code is shown below:
mydll.h:
#ifndef MYDLL_H
#define MYDLL_H
#include "mydll_global.h"
#include <QObject>
#include <QDebug>
class MYDLLSHARED_EXPORT MyDll : public QObject
{
Q_OBJECT
public:
explicit MyDll(QObject * parent = 0);
void test() const;
};
#endif // MYDLL_H
mydll_global.h:
#ifndef MYDLL_GLOBAL_H
#define MYDLL_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(MYDLL_LIBRARY)
# define MYDLLSHARED_EXPORT Q_DECL_EXPORT
#else
# define MYDLLSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // MYDLL_GLOBAL_H
mydll.cpp:
#include "mydll.h"
MyDll::MyDll(QObject * parent) :
QObject(parent)
{
}
void MyDll::test() const {
qDebug() << "Hello from dll!";
}
and the dll is used in another application. The dll is compiled successfully. I've add LIBS += "myDll.dll" in the .pro file of the application using this dll, and I've copied myDll.dll to the working directory of the application.
The compiler reports:
C4273: "MyDll::qt_static_metacall" : inconsistent dll linkage.
C2491: "MyDll::staticMetaObject": definition of dllimport static data member not allowed
What's the problem here?
Your code for mydll_global.h checks whether MYDLL_LIBRARY is defined, but none of the code you have posted defines MYDLL_LIBRARY. Is this declared in a file that you have not shared on the question? If not, you need to add a #define MYDLL_LIBRARY in your build project, or your PCH.

Resources