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
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 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
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'm trying to build a simple C++ program in Visual Studio 2017. I had no issues while doing it on Linux but for some reason it doesn't work on Windows.
Here is the program:
// CMakeProject1.cpp : Defines the entry point for the application.
//
#include "CMakeProject1.h"
#include "fmt/core.h"
#include "fmt/xchar.h"
#include "spdlog/sinks/win_eventlog_sink.h"
#include "spdlog/sinks/msvc_sink.h"
#include "spdlog/sinks/wincolor_sink.h"
#include "spdlog/spdlog.h"
#include <exception>
#include <vector>
int main()
{
std::vector<spdlog::sink_ptr> sinks;
sinks.push_back(std::make_shared<spdlog::sinks::win_eventlog_sink_mt>("me"));
sinks.push_back(std::make_shared<spdlog::sinks::msvc_sink_mt>());
sinks.push_back(std::make_shared<spdlog::sinks::wincolor_stdout_sink_mt>());
auto logger = std::make_shared<spdlog::logger>("main-logger", begin(sinks), end(sinks));
SPDLOG_LOGGER_CALL(logger, spdlog::level::info, L"{}", L"Hello World!");
return 0;
}
Here is my CMakeLists.txt
# CMakeList.txt : Top-level CMake project file, do global configuration
# and include sub-projects here.
#
cmake_minimum_required(VERSION 3.20)
get_filename_component(Project ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(REPLACE " " "-" Project ${Project})
project(${Project} CXX C)
set(CMAKE_VERBOSE_MAKEFILE ON)
include(FetchContent)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 8.0.1
)
FetchContent_MakeAvailable(fmt)
if (NOT fmt_POPULATED)
FetchContent_Populate(fmt)
add_subdirectory(${fmt_SOURCE_DIR} ${fmt_BINARY_DIR})
endif()
message(STATUS "fmt_SOURCE_DIR = ${fmt_SOURCE_DIR}")
message(STATUS "fmt_BINARY_DIR = ${fmt_BINARY_DIR}")
FetchContent_Declare(
spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.9.2
)
FetchContent_MakeAvailable(spdlog)
if (NOT spdlog_POPULATED)
FetchContent_Populate(spdlog)
set(SPDLOG_BUILD_EXAMPLES OFF)
set(SPDLOG_BUILD_BENCH OFF)
set(SPDLOG_BUILD_TESTS OFF)
add_subdirectory(${spdlog_SOURCE_DIR} ${spdlog_BINARY_DIR})
endif()
message(STATUS "spdlog_SOURCE_DIR = ${spdlog_SOURCE_DIR}")
message(STATUS "spdlog_BINARY_DIR = ${spdlog_BINARY_DIR}")
set(SourceDir ${CMAKE_CURRENT_SOURCE_DIR})
set(ExecutableSources ${SourceDir}/main.cpp)
set(LinkLibraries fmt::fmt spdlog::spdlog)
set(Executable ${Project})
message(STATUS CMAKE_VERSION = ${CMAKE_VERSION})
message(STATUS LinkLibraries = ${LinkLibraries})
add_executable(${Executable} ${ExecutableSources})
add_definitions(-DSPDLOG_WCHAR_TO_UTF8_SUPPORT)
target_compile_options(${Executable} PUBLIC ${CompilationFlags})
target_link_libraries(${Executable} PUBLIC ${LinkLibraries})
The way I generate a build files is the same way I do it on Linux
mkdir build
cd build
cmake ..
I then open the solution in Visual Studio 2017 and build it. However I'm getting the following errors:
4>main.cpp
4>main.obj : error LNK2019: unresolved external symbol "void __cdecl spdlog::details::os::wstr_to_utf8buf(class fmt::v8::basic_string_view<wchar_t>,class fmt::v8::basic_memory_buffer<char,250,class std::allocator<char> > &)" (?wstr_to_utf8buf#os#details#spdlog##YAXV?$basic_string_view#_W#v8#fmt##AAV?$basic_memory_buffer#D$0PK#V?$allocator#D#std###56##Z) referenced in function "protected: void __thiscall spdlog::logger::log_<wchar_t const (&)[13]>(struct spdlog::source_loc,enum spdlog::level::level_enum,class fmt::v8::basic_string_view<wchar_t>,wchar_t const (&)[13])" (??$log_#AAY0N#$$CB_W#logger#spdlog##IAEXUsource_loc#1#W4level_enum#level#1#V?$basic_string_view#_W#v8#fmt##AAY0N#$$CB_W#Z)
4>main.obj : error LNK2019: unresolved external symbol "void __cdecl spdlog::details::os::utf8_to_wstrbuf(class fmt::v8::basic_string_view<char>,class fmt::v8::basic_memory_buffer<wchar_t,250,class std::allocator<wchar_t> > &)" (?utf8_to_wstrbuf#os#details#spdlog##YAXV?$basic_string_view#D#v8#fmt##AAV?$basic_memory_buffer#_W$0PK#V?$allocator#_W#std###56##Z) referenced in function "protected: virtual void __thiscall spdlog::sinks::win_eventlog::win_eventlog_sink<class std::mutex>::sink_it_(struct spdlog::details::log_msg const &)" (?sink_it_#?$win_eventlog_sink#Vmutex#std###win_eventlog#sinks#spdlog##MAEXABUlog_msg#details#4##Z)
4>C:\Users\user\source\repos\CMakeProject1\build\Debug\CMakeProject1.exe : fatal error LNK1120: 2 unresolved externals
4>Done building project "CMakeProject1.vcxproj" -- FAILED.
========== Rebuild All: 3 succeeded, 1 failed, 0 skipped ==========
It looks like Visual Studio 2017 is not linking against the libraries. Does anyone know how to fix it?
Expanding on #fabian's comment, you should
set(SPDLOG_WCHAR_TO_UTF8_SUPPORT ON)
before the add_subdirectory call to have CMake set that preprocessor symbol for you.
I am subclassing QwtPlot. I have the following error:
moc_myplot.obj:-1: error: LNK2001: unresolved external symbol "public: static struct QMetaObject const QwtPlot::staticMetaObject" (?staticMetaObject#QwtPlot##2UQMetaObject##B)
I have tried to the following things: run qmake, rebuild, clean, delete debug folder, recompile qwt library. That doesn't help. Here is minimal code:
myplot.h:
#ifndef MYPLOT_H
#define MYPLOT_H
#include <QObject>
#include <qwt_plot.h>
class MyPlot : public QwtPlot
{
Q_OBJECT
public:
MyPlot();
};
#endif // MYPLOT_H
myplot.cpp:
#include "myplot.h"
MyPlot::MyPlot()
{
}
Here is .pro file:
#-------------------------------------------------
#
# Project created by QtCreator 2015-06-22T19:33:24
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = MyPlot
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
myplot.cpp
HEADERS += mainwindow.h \
myplot.h
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../../../qwt-6.1.2/lib/ -lqwt
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../../../qwt-6.1.2/lib/ -lqwtd
else:unix: LIBS += -L$$PWD/../../../../../qwt-6.1.2/lib/ -lqwt
INCLUDEPATH += $$PWD/../../../../../qwt-6.1.2/include
DEPENDPATH += $$PWD/../../../../../qwt-6.1.2/include
I am using Qt Creator 3.4.1 Based on Qt 5.4.2 (MSVC 2013, 32 bit). Kit: Desktop Qt 5.4.2 MSVC2013 64bit. Compiler: Microsof Visual C++ Compiler 12.0(amd64). If I comment Q_OBJECT macro in myplot.h everything is ok. I can use qwt_plot without subclassing, so that this->setCentralWidget(new QwtPlot()); line in mainwindow.cpp is ok.
It seems this is an old issue that was present in at least version 4.6.
The workaround is basically a preprocessor define of QWT_DLL from the "very lowest library that calls QWT".