I am trying to build a simple QT6 program using VSCode and MSVC. For this, I have following files:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.10.0)
project(test VERSION 0.1.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(test main.cpp mainwindow.cpp mainwindow.h)
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
target_link_libraries(test Qt6::Core Qt6::Widgets)
main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow()
: QMainWindow()
{
}
MainWindow::~MainWindow()
{
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
virtual ~MainWindow();
};
#endif // MAINWINDOW_H
I am using MSCV with Kit Visual Studio Community 2019 Release - x86_amd64.
My QT6 install is under C:\Qt and my Path varable contains C:\Qt\6.2.3\msvc2019_64
As I stated in the title, when I set Q_OBJECT for the MainWindow class, I get the following linker errors:
[build] mainwindow.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: virtual struct QMetaObject const * __cdecl MainWindow::metaObject(void)const " (?metaObject#MainWindow##UEBAPEBUQMetaObject##XZ)". [C:\Users\Nightbird\Desktop\test\build\test.vcxproj]
[build] mainwindow.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: virtual void * __cdecl MainWindow::qt_metacast(char const *)" (?qt_metacast#MainWindow##UEAAPEAXPEBD#Z)". [C:\Users\Nightbird\Desktop\test\build\test.vcxproj]
[build] mainwindow.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: virtual int __cdecl MainWindow::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall#MainWindow##UEAAHW4Call#QMetaObject##HPEAPEAX#Z)". [C:\Users\Nightbird\Desktop\test\build\test.vcxproj]
If I remove Q_OBJECT, the project compiles / links and runs. The problem is, for me to later implement Signal/Slot-Mechanisms, I need Q_OBJECT.
Now the linker errors suggest that something goes wrong after MOC creation, however I cant find the mistake I made. Do I have to change something in my CMakeList.txt?
So it seems I found out what the problem was...
I rearranged my CMakeList.txt like so:
cmake_minimum_required(VERSION 3.10.0)
project(test VERSION 0.1.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
add_executable(test main.cpp mainwindow.cpp mainwindow.h)
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
target_link_libraries(test Qt6::Core Qt6::Widgets)
Notice the position of the set()-Commands... That seemed to be it.
Now the output also shows [build] Automatic MOC and UIC for target test ... that didn't show before. So if you're struggling with linker errors regarding MOC, see if this line shows up. If it doesn't, check the order of cmake commands
Related
I'm currently attempted to use Qt project in the way that cmake compile project. I worked with Qt creator 4.11.1. I make new exercise in which the way of compilation is selected with cmake. It's most simple test. after all done,I used the cmake gui tool convert cmakelists to vs 2017 sln. the content of cmakelists was written in following sections:
cmake_minimum_required(VERSION 3.5)
project(Test_C LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check http://doc.qt.io/qt-5/deployment-android.html for more information.
# They need to be set before the find_package(Qt5 ...) call.
find_package(Qt5 COMPONENTS Widgets REQUIRED)
if(ANDROID)
add_library(Test_C SHARED
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
else()
add_executable(Test_C
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
endif()
target_link_libraries(Test_C PRIVATE Qt5::Widgets)
Then, Opening the sln by vs 2017, everything was well in first compile.However, it will get error message when I modified the mainwindow.h header file. It seems contain the marco Q_OBJECT, the error message is:
Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol "public: virtual void * __cdecl MainWindow::qt_metacast(char const *)" (?qt_metacast#MainWindow##UEAAPEAXPEBD#Z) Test_C D:\Alex\None-Working\Exercise\Qt\Test_C\Test_CB\Build\mainwindow.obj 1
Why is this happening (what did I do wrong), and how can I fix it (how do I do it right)?
Update:
There is no any specifical modification to mainwindow.h. otherwise, Adding the header file:
before modification:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
after modification:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <qstring.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
it may be not compiled if any modification occurred I guess. I do not insure whether moc compiler was worked in that time
I have here a class called engine and im trying to use, but when i include it i get LNK2019 error. Im running Visual Studio 2019 x86_64 compiler. Any ideas what could be wrong?
I have constructor and destructor defined in cpp file.
#pragma once
namespace NRD {
const int SCREEN_WIDTH(1280);
const int SCREEN_HEIGHT(720);
class Engine {
public:
Engine();
Engine(const Engine&) = delete;
Engine& operator=(const Engine&) = delete;
~Engine();
static Engine& Ref() {
static Engine reference;
return reference;
}
};
static Engine& Core = Engine::Ref();
}
Here is my cpp file:
#include "nrdengine/engine.h"
#include "nrdengine/service_locator.h"
#include "platform/glfw_window.h"
#include <iostream>
namespace NRD {
Engine::Engine() {
std::cout << "Initializing window!" << std::endl;
ServiceLocator::Provide(new CustomWindow());
}
Engine::~Engine() {
ServiceLocator::GetWindow()->DestroyWindow();
}
}
[build] main.obj : error LNK2019: unresolved external symbol "public: __cdecl NRD::Engine::Engine(void)" (??0Engine#NRD##QEAA#XZ) referenced in function "public: static class NRD::Engine & __cdecl NRD::Engine::Ref(void)" (?Ref#Engine#NRD##SAAEAV12#XZ) [C:\Users\Dawid\Desktop\NRD-Engine\build\nrdengine_cpp_application.vcxproj]
[build] main.obj : error LNK2019: unresolved external symbol "public: __cdecl NRD::Engine::~Engine(void)" (??1Engine#NRD##QEAA#XZ) referenced in function "void __cdecl `public: static class Engine::Ref & __cdecl NRD::Engine::Ref(void)'::`2'::`dynamic atexit destructor for 'reference''(void)" (??__Freference#?1??Ref#Engine#NRD##SAAEAV12#XZ#YAXXZ) [C:\Users\Dawid\Desktop\NRD-Engine\build\nrdengine_cpp_application.vcxproj]
[build] C:\Users\Dawid\Desktop\NRD-Engine\build\Debug\nrdengine_cpp_application.exe : fatal error LNK1120: 2 unresolved externals [C:\Users\Dawid\Desktop\NRD-Engine\build\nrdengine_cpp_application.vcxproj]
I have two CMakeList files (one for Engine project, one for App)
APP:
cmake_minimum_required(VERSION 3.5)
project(nrdengine_cpp_application VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
add_subdirectory(external/engine)
file(GLOB_RECURSE SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/*.c
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
#nrdengine_cpp_application.exe
add_executable(nrdengine_cpp_application ${SOURCE_FILES})
target_link_libraries(nrdengine_cpp_application PUBLIC nrdengine_cpp_engine)
target_include_directories(nrdengine_cpp_application PUBLIC nrdengine_cpp_engine)
ENGINE:
cmake_minimum_required(VERSION 3.5)
project(nrdengine_cpp_engine VERSION 0.0.1 LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
#add external libs
#find_package(OpenGL REQUIRED)
# install python and Jinja2
set(GLAD_SOURCES_DIR "${PROJECT_SOURCE_DIR}/external/glad")
add_subdirectory("${GLAD_SOURCES_DIR}/cmake" glad_cmake)
add_subdirectory(external/glfw)
add_subdirectory(external/glm)
add_subdirectory(external/assimp)
file(GLOB_RECURSE SOURCE_FILES
${CMAKE_SOURCE_DIR}/src/*.c
${CMAKE_SOURCE_DIR}/src/*.cpp)
glad_add_library(glad_gl_core_mx_31 REPRODUCIBLE MX API gl:core=3.1)
add_library(nrdengine_cpp_engine ${SOURCE_FILES})
target_include_directories(nrdengine_cpp_engine
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
glm
PRIVATE
glfw
assimp
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
glm
PRIVATE
glad_gl_core_mx_31
glfw
assimp
)```
I'm kinda guessing since your question is kinda hard to answer since it could be a lot of things. But here is my inference.
It's not recommended to glob your source files like you are doing here.
file(GLOB_RECURSE SOURCE_FILES
${CMAKE_SOURCE_DIR}/src/*.c
${CMAKE_SOURCE_DIR}/src/*.cpp)
NOTE: My suggestion requires 3.13 or higher version of CMake.
This causes lots of issues and might be the cause of your problems. Please see this post by one of the CMake maintainers on how to add source files to your project.
https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/
TLDR:
Make a CMakeLists.txt in your src/ directory like so.
target_sources(foobar PRIVATE
engine.cpp
engine.h
)
And make sure to call add_subdirectory(src) to process that new CMakeLists.txt
If you are interested in why globbing in build systems in general is bad. I can provide links.
I have a rather simple top-level CMakeLists.txt:
cmake_minimum_required(VERSION 3.14)
project(MyProject LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(Api)
add_subdirectory(Cli)
containing 2 subdirectories Api and Cli.
The API CMakeLists.txt is rather simple also:
cmake_minimum_required(VERSION 3.14)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)
add_library(Api
api.h
api.cpp
API_global.h)
target_link_libraries(Api Qt${QT_VERSION_MAJOR}::Core)
add_compile_definitions(API_LIBRARY)
The sources are trivial:
API_global.h
#ifndef API_GLOBAL_H
#define API_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(API_LIBRARY)
#define API_EXPORT Q_DECL_EXPORT
#else
#define API_EXPORT Q_DECL_IMPORT
#endif
#endif // API_GLOBAL_H
API.h
#ifndef API_H
#define API_H
#include "API_global.h"
class API_EXPORT API
{
public:
API() = default;
void printHello() const;
};
#endif // API_H
api.cpp
#include "api.h"
void API::printHello() const {}
The CLI subproject CMakeLists.txt then simply calls
find_library(API Api HINTS ${CMAKE_BINARY_DIR}/Api)
include_directories(${PROJECT_SOURCE_DIR}/Api)
target_link_libraries(cli PUBLIC ${API})
Within main.cpp a call to printHello fails with
main.cpp.obj:-1: error: LNK2019: unresolved external symbol "__declspec(dllimport) public: void __cdecl API::printHello(void)const " (__imp_?printHello#API##QEBAXXZ) referenced in function main
I first tested this on Mac where all is good. Fiddling around with this setup on Windows the entire morning but I cannot get my head around it. The find_library is returning the Api.lib as expected. My first guess would be that the API_LIBRARY is still defined in the Cli subproject but this is not the case apparently.
I must be missing something very obvious!
I have a simple CMake project:
proj (project folder)
├── a.h
├── a.cpp
└── CMakeLists.txt
CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_AUTOMOC ON)
project(proj)
set( proj_SOURCE
a.cpp
)
find_package(Qt5Core)
set( proj_LIBRARIES
Qt5::Core
)
add_library(proj SHARED ${proj_SOURCE})
target_link_libraries(proj ${proj_LIBRARIES})
a.h:
#pragma once
#include <QObject>
class A : public QObject
{
Q_OBJECT
public:
explicit A(QObject *parent = 0);
};
a.cpp:
#include "a.h"
A::A(QObject *parent) : QObject(parent)
{
}
and everything compiles great. Next, I tried to move the header file and the source file into different folder as so:
proj (project folder)
├── include
│ └── a.h
├── src
│ └── a.cpp
└── CMakeLists.txt
And tried different configurations of the following calls:
include_directories("include")
include_directories("src")
set( proj_SOURCE
src/a.cpp
)
Dosen't matter what I do the compilation fails with variations of
a.obj : error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __cdecl A::metaObject(void)const
" (?metaObject#A##UEBAPEBUQMetaObject##XZ) [C:\Users\me\AppData\Local\Temp\subclass\build\proj.vcxproj]
a.obj : error LNK2001: unresolved external symbol "public: virtual void * __cdecl A::qt_metacast(char const *)" (?qt_metacast#A
##UEAAPEAXPEBD#Z) [C:\Users\me\AppData\Local\Temp\subclass\build\proj.vcxproj]
a.obj : error LNK2001: unresolved external symbol "public: virtual int __cdecl A::qt_metacall(enum QMetaObject::Call,int,void *
*)" (?qt_metacall#A##UEAAHW4Call#QMetaObject##HPEAPEAX#Z) [C:\Users\me\AppData\Local\Temp\subclass\build\proj.vcxproj]
C:\Users\me\AppData\Local\Temp\subclass\build\Debug\proj.exe : fatal error LNK1120: 3 unresolved externals [C:\Users\me\Ap
pData\Local\Temp\subclass\build\proj.vcxproj]
I don't know if I need to set something extra for CMake to work or what the problem is. This answer says that CMake does not work well on this configuration (files on different folders), but maybe there is a way?
From the CMake users list: It seems like on this specific configuration one needs to add the header files to the target. I still dont know exactly why, but code below answers the above question.
cmake_minimum_required(VERSION 3.2)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_AUTOMOC ON)
project(proj)
set( proj_SOURCE
a.cpp
)
# add this
set( proj_HEADER
include/a.h
)
find_package(Qt5Core)
set( proj_LIBRARIES
Qt5::Core
)
# modify this
add_library(proj SHARED ${proj_SOURCE} ${proj_HEADER})
target_link_libraries(proj ${proj_LIBRARIES})
When using Qt 5.5, qmake and MSVC 13 to compile a basic, boilerplate Qt application with some fundamental OpenGL function calls, I get the following linker errors:
glwidget.obj:-1: error: LNK2019: unresolved external symbol __imp__glClear#4 referenced in function "public: virtual void __thiscall GLWidget::initializeGL(void)" (?initializeGL#GLWidget##UAEXXZ)
glwidget.obj:-1: error: LNK2019: unresolved external symbol __imp__glClearColor#16 referenced in function "public: virtual void __thiscall GLWidget::initializeGL(void)" (?initializeGL#GLWidget##UAEXXZ)
debug\OpenGLApp.exe:-1: error: LNK1120: 2 unresolved externals
I have:
Specified QT += opengl
Explicitly specified CONFIG += windows (apparently += console disables gui features)
the .pro file:
QT += core gui opengl widgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets opengl
TARGET = OpenGLApp
TEMPLATE = app
CONFIG += windows
SOURCES += main.cpp\
mainwindow.cpp \
glwidget.cpp
HEADERS += mainwindow.h \
glwidget.h
the glwidget.cpp file:
#include "glwidget.h"
GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent) {
}
void GLWidget::initializeGL() {
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
glwidget.h file:
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
class GLWidget : public QOpenGLWidget {
Q_OBJECT
public:
GLWidget(QWidget *);
void initializeGL();
void resizeGL();
void PaintGL();
};
In another virtually identical test program, I had the same problem of the linker being unable to resolve OpenGL function calls. By using CMake instead, specifically with the following "find_package(OpenGL REQUIRED)" line, and the addition of "${OPENGL_LIBRARIES}" in "target_link_libraries" I was able to solve the problem:
#Qt5
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5OpenGL REQUIRED)
#OpenGL
find_package(OpenGL REQUIRED)
target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::Gui Qt5::Core Qt5::OpenGL ${OPENGL_LIBRARIES})
I therefore suspect qmake is unable to find the OpenGL libraries, although I am unsure as how to check and what may be the cause of this, and so would appreciate if someone could point out to me what I'm missing.
You need to add in .pro file
LIBS += opengl32.lib
if you are using Visual Studio for correct linking of OpenGL libraries.
You can find some more details here:
http://doc.qt.io/qt-5/windows-requirements.html