Undefined reference to vtable using Qt - c++

I'm new to Qt and I'm trying to do a simple VoIP application.
I use CMake and conan to get all packages and build the application. If I place all Qt related class headers and sources files on the same directory, I can compile without any problem, but when I move the header files to another directory I found linker problems. I don't know why because in CMakeLists.txt I declare the include directories (and is working fine for others classes not related to Qt), I feel it's something related to autoMOC.
Project structure
|--include
| |
| |--client
| | |
| | |--views
| | | |
| | | |--loginwindow.ui
| | | |--ui_loginwindow.h
| | | |--mainwindow.ui
| | | |--ui_mainwindow.h
| | |--Client.h
| | |--loginWindow.h
| | |--mainWindow.h
| | |--Profile.h
| |--common
| |
| |--server
| |
|--src
| |
| |--client
| | |
| | |--Controller
| | |--Model
| | |--View
| | | |
| | | |--loginWindow.cpp
| | | |--mainWindow.cpp
| |--common
| |
| |--server
| |
I've ommited some directories content because the problem is not found there.
CMakeLists.txt
if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the source code and call cmake from there")
endif ()
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
project(babel)
cmake_minimum_required(VERSION 3.17.4)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_definitions("-fPIC")
if(MSVC)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
else()
set(STANDARD_UNIX_CXX_FLAGS "-Wall -g3 -Wextra -Wfatal-errors")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STANDARD_UNIX_CXX_FLAGS}")
endif()
if (EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
else()
message(FATAL_ERROR "No conanbuildinfo.cmake file found")
endif()
conan_basic_setup(KEEP_RPATHS)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt5OpenGL CONFIG REQUIRED)
find_package(Qt5Widgets CONFIG REQUIRED)
find_package(Qt5Core CONFIG REQUIRED)
find_package(Qt5Gui CONFIG REQUIRED)
find_package(Qt5Network CONFIG REQUIRED)
find_package(portaudio REQUIRED)
find_package(Opus REQUIRED)
find_package(asio REQUIRED)
file(
GLOB_RECURSE
SOURCES_CLIENT
${PROJECT_SOURCE_DIR}/src/*.cpp
${PROJECT_SOURCE_DIR}/src/client/*.cpp
${PROJECT_SOURCE_DIR}/include/client/*.hpp
${PROJECT_SOURCE_DIR}/include/client/*.ui
${PROJECT_SOURCE_DIR}/resources.qrc
)
file(
GLOB_RECURSE
SOURCES_SERVER
${PROJECT_SOURCE_DIR}/src/server/*.cpp
)
file(
GLOB_RECURSE
SOURCES_COMMON
${PROJECT_SOURCE_DIR}/src/common/*.cpp
${PROJECT_SOURCE_DIR}/include/common/*.hpp
)
add_executable(babel_client ${SOURCES_CLIENT} ${SOURCES_COMMON})
install(TARGETS babel_client DESTINATION ${PROJECT_SOURCE_DIR}/bin)
target_link_libraries(
babel_client
Qt5::Widgets
Qt5::Network
Qt5::OpenGL
Qt5::Core
Qt5::Gui
opus
portaudio
)
target_include_directories(
babel_client PRIVATE
${CONAN_INCLUDE_LIBS}
${PROJECT_SOURCE_DIR}/include/client
${PROJECT_SOURCE_DIR}/include/client/views
${PROJECT_SOURCE_DIR}/include/common
)
loginWindow.h
#ifndef LOGINWINDOW_H
#define LOGINWINDOW_H
#include <QMainWindow>
#include "mainWindow.h"
#include "views/ui_loginwindow.h"
#include <QKeyEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class LoginWindow; }
QT_END_NAMESPACE
class LoginWindow : public QMainWindow
{
Q_OBJECT
public:
LoginWindow(QWidget *parent = nullptr);
~LoginWindow();
private slots:
void on_loginButton_clicked();
protected:
void keyPressEvent(QKeyEvent *key);
private:
Ui::LoginWindow *ui;
MainWindow *mainWindow;
};
#endif // LOGINWINDOW_H
loginWindow.cpp
#include "loginWindow.h"
#include <QPixmap>
LoginWindow::LoginWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::LoginWindow)
{
int picWidth;
int picHeight;
ui->setupUi(this);
QPixmap pix(":/resources/babel.png");
picWidth = ui->babelPicture->width();
picHeight = ui->babelPicture->height();
ui->babelPicture->setPixmap(pix.scaled(picWidth, picHeight, Qt::KeepAspectRatio));
ui->statusbar->addPermanentWidget(ui->statusText);
ui->loginButton->setDefault(true);
}
LoginWindow::~LoginWindow()
{
delete (ui);
}
void LoginWindow::keyPressEvent(QKeyEvent *key)
{
if (key->key() == Qt::Key_Return)
on_loginButton_clicked();
}
void LoginWindow::on_loginButton_clicked()
{
QString user = ui->userField->text();
QString pass = ui->passwordField->text();
if (user == "test" && pass == "test") {
ui->statusText->setText("Correct login");
this->hide();
mainWindow = new MainWindow(this);
mainWindow->show();
} else{
ui->statusText->setText("Inorrect login");
}
}
mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "views/ui_mainwindow.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainWindow.cpp
#include "mainWindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
Linker output
/usr/bin/ld: CMakeFiles/babel_client.dir/src/client/View/loginWindow.cpp.o: in function `LoginWindow::~LoginWindow()':
/home/bltksk/epitech/tek3/CPP/babel/src/client/View/loginWindow.cpp:20: undefined reference to `vtable for LoginWindow'
/usr/bin/ld: CMakeFiles/babel_client.dir/src/client/View/loginWindow.cpp.o: in function `non-virtual thunk to LoginWindow::~LoginWindow()':
/home/bltksk/epitech/tek3/CPP/babel/src/client/View/loginWindow.cpp:23: undefined reference to `vtable for LoginWindow'
/usr/bin/ld: CMakeFiles/babel_client.dir/src/client/View/loginWindow.cpp.o: in function `LoginWindow::LoginWindow(QWidget*)':
/home/bltksk/epitech/tek3/CPP/babel/src/client/View/loginWindow.cpp:6: undefined reference to `vtable for LoginWindow'
/usr/bin/ld: CMakeFiles/babel_client.dir/src/client/View/mainWindow.cpp.o: in function `MainWindow::MainWindow(QWidget*)':
/home/bltksk/epitech/tek3/CPP/babel/src/client/View/mainWindow.cpp:5: undefined reference to `vtable for MainWindow'
/usr/bin/ld: CMakeFiles/babel_client.dir/src/client/View/mainWindow.cpp.o: in function `MainWindow::~MainWindow()':
/home/bltksk/epitech/tek3/CPP/babel/src/client/View/mainWindow.cpp:10: undefined reference to `vtable for MainWindow'
/usr/bin/ld: CMakeFiles/babel_client.dir/src/client/View/mainWindow.cpp.o: in function `non-virtual thunk to MainWindow::~MainWindow()':
/home/bltksk/epitech/tek3/CPP/babel/src/client/View/mainWindow.cpp:13: undefined reference to `vtable for MainWindow'
As I've said on the introduction, if I place xxWindow.h and xxWindow.cpp on the same folder, the problem disappears, but when I place them on the include directory it doesn't link. I'm not a cmake expert, but it seems right to me. Any hint about the solution?

Okay, I achieved to solve the problem.
In order to make AUTOUIC function correctly, we have to add all the headers that includes ui_*.h to the sources target and not only to the include path. This way automoc will correctly process the headers and it will be correctly linked.
In my case it is like this:
file(
GLOB_RECURSE
SOURCES_CLIENT
${PROJECT_SOURCE_DIR}/src/*.cpp
${PROJECT_SOURCE_DIR}/src/client/*.cpp
${PROJECT_SOURCE_DIR}/include/client/*.h
${PROJECT_SOURCE_DIR}/include/client/resources/resources.qrc
)
Also, remember to set CMAKE_AUTOUIC_SEARCH_PATHS (cmake version >3.9) with the path where .ui files are located, if not, there will be an AutoUic error.
I hope this will help somebody in the future.

Related

How to make C++ header file use 3rd party headers while only exposing a limited API when said headers are included in the src folder CMakeLists file?

This is my first larger-scale project using CMake, so please bear with me because I might be going about this wrong.
I have the following code, to open a GLFWwindow, and start setting up a VkInstance with Vulkan. My problem is that this version works fine,
but I can use GLFW components from the EngineDemo.cpp file. This is due to GameEngine/VulkanEngine/Renderer/src/CMakeLists.txt including the glfw3.h
file as a PUBLIC header. I would like to know if there is a way to be able to use glfw3.h inside VulkanRenderer.h without exposing it to the
API consumer EngineDemo.cpp. Also, CMake should be able to only give the right release version (Debug, RelWithDebugInfo, Release) of the glfw3.h and glfw3.lib to
VulkanRenderer.h.
I have the Vulkan SDK with all the components (glfw3, glm) installed on this path:
C:\VulkanSDK\1.3.236.0
And I have the following structure in a CLion C++ project using CMake and Microsoft's MSVC compiler version 1929:
GameEngine
|-- Libs
| |-- Windows
| | |-- DebugBuild
| | | |-- glfw3
| | | | |-- lib
| | | | | |-- glfw3.lib
| | | | |-- include
| | | | | |-- glfw3.h
| | | | | |-- glfw3native.h
| | |-- RelWithDebInfoBuild
| | | |-- ...
| | |-- ReleaseBuild
| | | |-- ...
| |-- Linux (same structure as Windows folder)
|-- EngineDemo
| |-- CMakeLists.txt
| |-- include
| | |-- EngineDemo
| | | |-- empty
| |-- src
| | |-- EngineDemo.cpp
| | |-- CMakeLists.txt
|-- VulkanEngine
| |-- CMakeLists.txt
| |-- Renderer
| | |-- CMakeLists.txt
| | |-- include
| | | |-- Renderer
| | | | |-- VulkanRenderer.h
| | |-- src
| | | |-- VulkanRenderer.cpp
| | | |-- CMakeLists.txt
|-- CMakeLists.txt
GameEngine/CMakeLists.txt content:
cmake_minimum_required(VERSION 3.24)
project(VulkanEngine)
set(CMAKE_CXX_STANDARD 17)
set(DEBUG_WIN32_LIB_PATH "${CMAKE_SOURCE_DIR}/Libs/Windows/DebugBuild")
set(RELEASE_WITH_DEB_INFO_WIN32_LIB_PATH "${CMAKE_SOURCE_DIR}/Libs/Windows/RelWithDebInfoBuild")
set(RELEASE_WIN32_LIB_PATH "${CMAKE_SOURCE_DIR}/Libs/Windows/ReleaseBuild")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(GLFW3_INCLUDE_PATH "${DEBUG_WIN32_LIB_PATH}/glfw3/include")
set(GLFW3_LIB_PATH "${DEBUG_WIN32_LIB_PATH}/glfw3/lib/glfw3.lib")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# using Visual Studio C++
add_definitions(-D_ITERATOR_DEBUG_LEVEL=2)
endif()
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(GLFW3_INCLUDE_PATH "${RELEASE_WITH_DEB_INFO_WIN32_LIB_PATH}/glfw3/include")
set(GLFW3_LIB_PATH "${RELEASE_WITH_DEB_INFO_WIN32_LIB_PATH}/glfw3/lib/glfw3.lib")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# using Visual Studio C++
add_definitions(-D_ITERATOR_DEBUG_LEVEL=0)
endif()
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
set(GLFW3_INCLUDE_PATH "${RELEASE_WIN32_LIB_PATH}/glfw3/include")
set(GLFW3_LIB_PATH "${RELEASE_WIN32_LIB_PATH}/glfw3/lib/glfw3.lib")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# using Visual Studio C++
add_definitions(-D_ITERATOR_DEBUG_LEVEL=0)
endif()
endif()
# Include sub-projects.
add_subdirectory ("VulkanEngine")
add_subdirectory ("EngineDemo")
GameEngine/EngineDemo/CMakeLists.txt content:
add_subdirectory(src)
GameEngine/EngineDemo/src/CMakeLists.txt content:
project(EngineDemo)
add_executable (${PROJECT_NAME} EngineDemo.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC ../include)
target_link_libraries(${PROJECT_NAME} PUBLIC VulkanEngineModule)
GameEngine/EngineDemo/src/EngineDemo.cpp content:
#include <iostream>
#include <cstdlib>
#include <stdexcept>
#include "Renderer/VulkanRenderer.h"
int main()
{
VulkanRenderer app;
try {
app.run();
} catch (const std::exception &exception) {
std::cerr << exception.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
GameEngine/VulkanEngine/CMakeLists.txt content:
add_subdirectory(Renderer)
GameEngine/VulkanEngine/Renderer/CMakeLists.txt content:
add_subdirectory(src)
GameEngine/VulkanEngine/Renderer/include/Renderer/VulkanRenderer.h content:
#pragma once
#define GLFW_INCLUDE_VULKAN
#include "glfw3.h"
class VulkanRenderer {
private:
VkInstance vkInstance;
GLFWwindow* window = nullptr;
public:
void run();
private:
void initWindow();
void initVulkan();
void mainLoop();
void cleanup();
void createVulkanInstance();
};
GameEngine/VulkanEngine/Renderer/src/CMakeLists.txt content:
cmake_minimum_required (VERSION 3.24)
project(VulkanEngineModule)
add_library (${PROJECT_NAME} STATIC VulkanRenderer.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC ../include)
find_package(Vulkan REQUIRED)
if(Vulkan_FOUND)
target_include_directories(${PROJECT_NAME} PUBLIC ${Vulkan_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} INTERFACE ${Vulkan_LIBRARIES})
endif(Vulkan_FOUND)
if(WIN32)
target_include_directories(${PROJECT_NAME} PUBLIC ${GLFW3_INCLUDE_PATH})
target_link_libraries(${PROJECT_NAME} INTERFACE ${GLFW3_LIB_PATH})
endif(WIN32)
GameEngine/VulkanEngine/Renderer/src/VulkanRenderer.cpp content:
#ifdef _WIN32
#include <Windows.h>
#endif
#include "Renderer/VulkanRenderer.h"
void VulkanRenderer::run() {
initWindow();
initVulkan();
mainLoop();
cleanup();
}
void VulkanRenderer::initWindow() {
const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;
const char* WINDOW_TITLE = "Vulkan Engine";
glfwInit();
VkInstance c;
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, WINDOW_TITLE, nullptr, nullptr);
}
void VulkanRenderer::initVulkan() {
createVulkanInstance();
}
void VulkanRenderer::mainLoop() {
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
}
}
void VulkanRenderer::cleanup() {
glfwDestroyWindow(window);
glfwTerminate();
}
void VulkanRenderer::createVulkanInstance() {
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Hello Triangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
}
If I move the VkInstance and GLFWwindow declarations and the glfw3.h header include macro to the VulkanRenderer.cpp file
with the #define GLFW_INCLUDE_VULKAN alongside it and change the target_include_directories to PRIVATE for the GLFW_INCLUDE_PATH in GameEngine/VulkanEngine/Renderer/src/CMakeLists.txt
an empty window opens when I run the EngineDemo.exe; this does not expose lower-level functions to EngineDemo.cpp either. But this is not the goal.
I would like to declare every member variable of the VulkanRenderer class in the corresponding header file.
I tried to change GameEngine/VulkanEngine/Renderer/include/Renderer/VulkanRenderer.h to this:
#pragma once
#define GLFW_INCLUDE_VULKAN
#include "Renderer/glfw_config.h"
class VulkanRenderer {
private:
VkInstance vkInstance;
GLFWwindow* window = nullptr;
public:
void run();
private:
void initWindow();
void initVulkan();
void mainLoop();
void cleanup();
void createVulkanInstance();
};
Added a glfw_config.h.in file to the GameEngine/VulkanEngine/Renderer/src folder that looked like this:
#pragma once
#include "#GLFW3_INCLUDE_PATH#/glfw3.h"
Appended these two lines to the end of GameEngine/VulkanEngine/Renderer/src/CMakeLists.txt:
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/glfw_config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/../include/Renderer/glfw_config.h" #ONLY)
target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/../include")
The resulting glfw_config.h file in GameEngine/cmake-build-debug-visual-studio/VulkanEngine/Renderer/include/Renderer has the following content:
#pragma once
#include "C:/Projects/GameEngine/Libs/Windows/DebugBuild/glfw3/include/glfw3.h"
The above path to the header file is the correct one, and this works just like the previous setup.
If this line target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/../include") changes to INTERFACE or PRIVATE then Renderer/glfw_config.h cannot be found.
My idea was that if I generate the proper glfw_config.h header file with the appropriate absolute path when reloading the CMake project, I would be able to
finally, use glfw3.h in all different run configurations from the VulkanRenderer.h header file and not expose it to the outside world if I set the above-mentioned visibility to INTERFACE or PRIVATE.
Is there a way to automatically generate this #include path with CMake depending on which release I am building my project on and to only keep the GLFW components found in glfw3.h and by extension, all components in vulkan.h inside the GameEngine/VulkanEngine project only, and expose a limited API to the EngineDemo project?
If this is not possible with just the use of CMake, I would also greatly appreciate any suggestions on how to restructure the project the achieve the desired effect.
I tried googling for a similar question already, but the automatic system of StackOverflow didn't detect any duplicates either.
After trying for a day to formulate a more generic question and researching for it, I found out about a new use case for header files here.
This seems to work perfectly well in my application when the VkInstance and GLFWwindow * are declared in the private header instead of the public one.
When the private header is the one that has these macros:
#define GLFW_INCLUDE_VULKAN
#include "glfw3.h"
I can still easily control the propagation of the 3rd party header files with CMake to higher levels on the dependency graph.

Cant find SDL.h - Windows, MingW, Cmake and SLD2 (in VSCode with CPP)

I want to add SDL2 to a Cmake Project, using C++ in VSCode on Windows, but using Mingw64 from Msys2 (g++).
This is my current CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(TileGameStudio_Runtime LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(PROJ_SRC
${PROJECT_SOURCE_DIR}/src
)
add_subdirectory(${PROJECT_SOURCE_DIR}/SDL2)
include_directories(${PROJECT_SOURCE_DIR}/SDL2/include)
file(GLOB PROJECT_SOURCES CONFIGURE_DEPENDS
${PROJ_SRC}/*.cpp
)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}\\Game")
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}\\Game")
# add the executable
add_executable(TileGameStudio_Runtime
${PROJECT_SOURCES}
)
target_link_libraries(TileGameStudio_Runtime PRIVATE
SDL2-static
SDL2main
)
set_target_properties(
TileGameStudio_Runtime
PROPERTIES
OUTPUT_NAME "Game"
SUFFIX ".exe"
)
This is my current Project Structure (img)
As you can see. i cloned the Repo from https://github.com/libsdl-org/SDL as a subdirectory to my Project. And this, i added via cmake add_subdirectory.
My Main.cpp is simply this:
#include <iostream>
#include <vector>
#include <string>
#include <SDL.h>
#ifdef main
# undef main
#endif /* main */
using namespace std;
int main(int argc, char *argv[]) {
SDL_Window *win = NULL;
SDL_Renderer *renderer = NULL;
int posX = 100, posY = 100, width = 320, height = 240;
SDL_Init(SDL_INIT_VIDEO);
win = SDL_CreateWindow("Hello World", posX, posY, width, height, 0);
renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
//================================================ Draw a Text
//this opens a font style and sets a size
TTF_Font* Sans = TTF_OpenFont("Sans.ttf", 24);
// this is the color in rgb format,
// maxing out all would give you the color white,
// and it will be your text's color
SDL_Color White = {255, 255, 255};
// as TTF_RenderText_Solid could only be used on
// SDL_Surface then you have to create the surface first
SDL_Surface* surfaceMessage = TTF_RenderText_Solid(Sans, "put your text here", White);
SDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, surfaceMessage);
SDL_Rect Message_rect; //create a rect
Message_rect.x = 0; //controls the rect's x coordinate
Message_rect.y = 0; // controls the rect's y coordinte
Message_rect.w = 100; // controls the width of the rect
Message_rect.h = 100; // controls the height of the rect
SDL_RenderCopy(renderer, Message, NULL, &Message_rect);
//================================================ Draw a Text End
while (1) {
SDL_Event e;
if (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
break;
}
}
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
Which should create a Window.. and perhaps draw a text to it.
But, SDL.h can´t be found... so i can´t build the Stuff here..
I updated my CMakeLists.txt, cause i reinstalled the whole msys2 (since of a installation problem).
This is the new One:
cmake_minimum_required(VERSION 3.5)
project(TileGameStudio_Runtime LANGUAGES CXX)
set(CMAKE_CXX_FLAGS -v)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(PROJ_SRC
${PROJECT_SOURCE_DIR}/src
)
file(GLOB PROJECT_SOURCES CONFIGURE_DEPENDS
${PROJ_SRC}/*.cpp
)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}\\Game")
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}\\Game")
INCLUDE(FindPkgConfig)
pkg_check_modules(SDL2 REQUIRED sdl2)
pkg_check_modules(SDL2_IMAGE REQUIRED SDL2_image)
pkg_check_modules(SDL2_TTF REQUIRED SDL2_ttf)
pkg_check_modules(SDL2_MIXER REQUIRED SDL2_mixer)
include_directories(
${SDL2_INCLUDE_DIRS}
${SDL2_IMAGE_INCLUDE_DIRS}
${SDL2_TTF_INCLUDE_DIRS}
${SDL2_MIXER_INCLUDE_DIRS}
)
link_directories (
${SDL2_LIBRARY_DIRS}
${SDL2_IMAGE_LIBRARY_DIRS}
${SDL2_TTF_LIBRARY_DIRS}
${SDL2_MIXER_LIBRARY_DIRS}
)
# add the executable
add_executable(TileGameStudio_Runtime
${PROJECT_SOURCES}
)
target_link_libraries (TileGameStudio_Runtime
${SDL2_LIBRARIES}
${SDL2_IMAGE_LIBRARIES}
${SDL2_TTF_LIBRARIES}
${SDL2_MIXER_LIBRARIES}
)
set_target_properties(
TileGameStudio_Runtime
PROPERTIES
OUTPUT_NAME "Game"
SUFFIX ".exe"
)
I installed the whole mingw64 toolchain and SDL2 via msys (under MingW64 Mode of msys2) now.
it still couldn´t find the SDL.h or SDL2/SDL.h
I checked the SDL2_Dir in the Cmake GUI.. and it has the correct Path to: "C:/msys64/mingw64/lib/cmake/SDL2"
EDIT:
I now changed the Main Folder of all my Projects (unreal, unity..etc) from "Game Design" to "Game_Design".. Working like a Charm now... Cause.. Spaces are evil.. very evil...
Thanks for your Help Trys :D <3

c++ Qt inheriting from QWidget gives linking error re missing vtable

I am on MacOS and I want to inherit QWidget for a class with QObject :: connect but i have a error:
Undefined symbols for architecture x86_64:
"vtable for Core", referenced from:
Core::Core(QWidget*) in Core.cpp.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [bin/babel] Error 1
make[1]: *** [CMakeFiles/babel.dir/all] Error 2
Core.cpp
** EPITECH PROJECT, 2020
** Babel
** File description:
** Core
*/
#include "../include/Core.hpp"
Core::Core(QWidget *parent) : QWidget(parent)
{
this->text = new QLabel("Pseudo", this);
this->textArea = new QTextEdit(this);
this->button = new QPushButton("Connexion", this);
QObject::connect(this->button, SIGNAL(clicked()), this, SLOT(this->buttonPushed()));
this->button->setGeometry(300, 250, 160, 30);
this->textArea->setGeometry(300, 200, 160, 30);
this->text->setGeometry(335, 175, 160, 30);
}
Core::~Core()
{
}
void Core::buttonPushed()
{
printf("EKIP EKIP EKIP\n");
}
Core.hpp:
/*
** EPITECH PROJECT, 2020
** Babel
** File description:
** Core
*/
#ifndef CORE_HPP_
#define CORE_HPP_
#include <stdio.h>
#include <stdlib.h>
#include <opus/opus.h>
#include <portaudio.h>
#include <QtWidgets>
class Core : public QWidget {
Q_OBJECT
public:
explicit Core(QWidget *parent = nullptr);
~Core();
protected:
private slots:
void buttonPushed();
private:
// QApplication *app;
QPushButton *button;
QLabel *text;
QTextEdit *textArea;
};
#endif /* !CORE_HPP_ */
and Main.cpp
/*
** EPITECH PROJECT, 2020
** Babel
** File description:
** main
*/
#include "../include/Core.hpp"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Core *core = new Core();
core->setGeometry(10, 10, 720, 480);
core->setWindowTitle("Babel");
core->show();
return app.exec();
}
Cmake file:
project(Babel)
cmake_minimum_required(VERSION 2.8.12)
add_definitions("-fPIC")
SET(CMAKE_AUTOMOC ON)
SET(CMAKE_AUTOUIC ON)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Core)
find_package(Qt5Network)
file(GLOB_RECURSE BABEL_SRC PATH ./sources/*.cpp)
include_directories(${CMAKE_INCLUDE_PATH})
add_executable(babel ${BABEL_SRC})
target_link_libraries(babel ${CONAN_LIBS} Qt5::Widgets Qt5::Core Qt5::Network)
add the files with Q_OBJECT in the cmake like this for example :
set(SOURCES core.cpp )
qt5_wrap_cpp(SOURCES core.hpp)
add_executable(babel ${SOURCES} ${BABEL_SRC})

Library linking error: undefined reference to _imp__

I can't figure out how to link FTDI library in my Qt project. I copied ftd2xx.h file to my project directory. The file I want to link is dll: ftd2xx.lib which is stored in F:\Workspace\qt\libs\ftdi\amd64
I get error:
release/testftdi.o:testftdi.cpp:(.text+0x6f8): undefined reference to `_imp__FT_Open#8'
collect2.exe: error: ld returned 1 exit status
I have QtWidget application with one PushButton:
TestFtdi.pro file:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = TestFtdi
TEMPLATE = app
LIBS += -L"F:\Workspace\qt\libs\ftdi\amd64" -lftd2xx
INCLUDEPATH += f:/Workspace/qt/libs/ftdi/amd64
SOURCES += main.cpp\
testftdi.cpp
HEADERS += testftdi.h
FORMS += testftdi.ui
main.cpp file:
#include "testftdi.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TestFtdi w;
w.show();
return a.exec();
}
testftdi.h file:
#ifndef TESTFTDI_H
#define TESTFTDI_H
#include <QMainWindow>
namespace Ui {
class TestFtdi;
}
class TestFtdi : public QMainWindow
{
Q_OBJECT
public:
explicit TestFtdi(QWidget *parent = 0);
~TestFtdi();
private slots:
void on_pushButton_clicked();
private:
Ui::TestFtdi *ui;
};
#endif // TESTFTDI_H
testftdi.cpp file:
#include "testftdi.h"
#include "ui_testftdi.h"
#include <QDebug>
#include "windows.h"
#include "ftd2xx.h"
TestFtdi::TestFtdi(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TestFtdi)
{
ui->setupUi(this);
}
TestFtdi::~TestFtdi()
{
delete ui;
}
void TestFtdi::on_pushButton_clicked()
{
FT_HANDLE ftHandle;
FT_STATUS ftStatus;
ftStatus = FT_Open(0, &ftHandle);
if(ftStatus != FT_OK) { // FT_Open failed
qDebug() << "FT_Open failed";
}
}
The compiler command looks in this situation like this:
g++ -Wl,-s -Wl,-subsystem,windows -mthreads -o release\TestFtdi.exe release/main.o release/testftdi.o release/moc_testftdi.o -lmingw32 -LC:/Qt/5.5/mingw492_32/lib -lqtmain -lshell32 -LF:\Workspace\qt\libs\ftdi\Static\amd64 -lftd2xx -lQt5Widgets -lQt5Gui -lQt5Core
Could you help me with this?
My guess is, compiler might be looking for ftd2xx rather than ftd2xx.lib (file name is ftd2xx.lib.dll, right?). Have you tried changing the LIBS line to
LIBS += -L"F:\Workspace\qt\libs\ftdi\amd64" -lftd2xx.lib

Qt + CMake + VC++ produce a command prompt

I am using the combination mentioned in the title while trying to run the window layout example from the qt tutorials. The main looks like this:
#include <QtGui>
int main(int argc, char **argv) {
QApplication app(argc, argv);
QWidget window;
QLabel *label = new QLabel(QApplication::translate("windowlayout", "Name:"));
QLineEdit *lineEdit = new QLineEdit();
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget(label);
layout->addWidget(lineEdit);
window.setLayout(layout);
window.setWindowTitle(
QApplication::translate("windowlayout", "Window layout"));
window.show();
return app.exec();
}
And the CMakeLists.txt like this:
PROJECT(test)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)
FIND_PACKAGE(Qt4 REQUIRED)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR} ${QT_QTCORE_INCLUDE_DIR} ${QT_QTGUI_INCLUDE_DIR})
SET(test_SRCS main.cc)
QT4_AUTOMOC(${test_SRCS})
ADD_EXECUTABLE(test ${test_SRCS})
TARGET_LINK_LIBRARIES(test ${QT_QTGUI_LIBRARIES} ${QT_QTCORE_LIBRARIES})
The building and compilation work properly but when I run the application, it always show a command prompt. How do I avoid that?
You need to tell CMake that you want a GUI application:
# GUI Type
if(WIN32)
set(GUI_TYPE WIN32)
endif(WIN32)
if(APPLE)
set(GUI_TYPE MACOSX_BUNDLE)
endif(APPLE)
ADD_EXECUTABLE(test ${GUI_TYPE} ${test_SRCS})
Note that when you are compiling on Windows, this will change the program entry from main() to WinMain(), so you will need to modify your sources as well.
Here's what I usually do:
#ifdef _WIN32
class Win32CommandLineConverter;
int CALLBACK WinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, LPSTR /* lpCmdLine */, int /* nCmdShow */)
{
Win32CommandLineConverter cmd_line;
return main(cmd_line.argc(), cmd_line.argv());
}
class Win32CommandLineConverter {
private:
std::unique_ptr<char*[]> argv_;
std::vector<std::unique_ptr<char[]>> storage_;
public:
Win32CommandLineConverter()
{
LPWSTR cmd_line = GetCommandLineW();
int argc;
LPWSTR* w_argv = CommandLineToArgvW(cmd_line, &argc);
argv_ = std::unique_ptr<char*[]>(new char*[argc]);
storage_.reserve(argc);
for(int i=0; i<argc; ++i) {
storage_.push_back(ConvertWArg(w_argv[i]));
argv_[i] = storage_.back().get();
}
LocalFree(w_argv);
}
int argc() const
{
return static_cast<int>(storage_.size());
}
char** argv() const
{
return argv_.get();
}
static std::unique_ptr<char[]> ConvertWArg(LPWSTR w_arg)
{
int size = WideCharToMultiByte(CP_UTF8, 0, w_arg, -1, nullptr, 0, nullptr, nullptr);
std::unique_ptr<char[]> ret(new char[size]);
WideCharToMultiByte(CP_UTF8, 0, w_arg, -1, ret.get(), size, nullptr, nullptr);
return ret;
}
};
#endif
I wanted a release build to hide the console but all other builds to show it. To do that use:
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
SET_TARGET_PROPERTIES(MyApp PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
SET_TARGET_PROPERTIES(MyApp PROPERTIES RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
SET_TARGET_PROPERTIES(MyApp PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
SET_TARGET_PROPERTIES(MyApp PROPERTIES MINSIZEREL "/SUBSYSTEM:WINDOWS")
endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
This will introduce the following linker error:
error LNK2019: unresolved external symbol _WinMain#16 referenced in function ___tmainCRTStartup
to fix it link with QT_QTMAIN_LIBRARY in your CMakeLists.txt file
TARGET_LINK_LIBRARIES(MyApp ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY} ${OTHER_STUFF_TO_LINK})
Now you don't even have to change your sources as was done in the previous solution.
In your CMakeFile with Qt4, you don't need to change your CPP code or to add flags at compile time. Simply use
set(QT_USE_QTMAIN TRUE)
It will automatically link qtmain.lib with your executable. This library defines other common main() signatures, including WinMain().
With this trick, your app can compile with MSVC under Windows, without mofiying your original main() function and without displaying a console when you run your app outside of your IDE (QtCreator for example).
Final resulting CMakeLists.txt can be :
PROJECT(test)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)
FIND_PACKAGE(Qt4 REQUIRED)
if(WIN32)
SET(QT_USE_QTMAIN TRUE)
endif(WIN32)
INCLUDE(${QT_USE_FILE})
SET(test_SRCS main.cc)
QT4_AUTOMOC(${test_SRCS})
ADD_EXECUTABLE(test ${test_SRCS})
TARGET_LINK_LIBRARIES(test ${QT_LIBRARIES})
Additionnaly, you don't need to include QtCore and QtGui, they are included by default with QT_USE_FILE (for include folders) and QT_LIBRARIES (for libraries).
You only have to set what modules you use, or you don't use (for Gui) :
# Use Network and Sql modules
set(QT_USE_QTNETWORK TRUE)
set(QT_USE_QTSQL TRUE)
# Do not use Gui module
set(QT_DONT_USE_QTGUI TRUE)
in the pro file, remove the following console definition and it will go
CONFIG += console