c++gcccmakeqt6ninja

undefined reference to `qMain(int, char**)' error with msys2 / ucrt / gcc 12, c++ 23, qt6 and cmake


I'm trying to compile a simple C++ / Qt program on windows 10 using:

I'm not using any IDE nor power shell, just notepad++ and the windows command prompt.

My program.cpp is:

#include <QApplication>
#include <QLabel>

int main()
{
    int argc = 1;
    const char* argv[1] { "prog" };
    QApplication app { argc, const_cast<char**>(argv) };
    QLabel *label = new QLabel("Hello Qt!");
    label->show();
    return app.exec();
}

toolchain.cmake:

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_C_COMPILER gcc)
set(CMAKE_CXX_COMPILER g++)

My configure.bat is this:

cmake -G "Ninja" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON .

My CMakeLists.txt is this:

cmake_minimum_required(VERSION 3.16)

set(CMAKE_VERBOSE_MAKEFILE on)

project(test_cmake_qt VERSION 0.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
qt_standard_project_setup()

qt_add_executable(program_qt_gpp_cmake 
    program.cpp
)

target_compile_options(program_qt_gpp_cmake PRIVATE -pedantic -Wall -Wextra -Werror=return-type -Wshadow=local -Wempty-body -fno-ms-extensions -fdiagnostics-color -s -Os -fmax-errors=3)

target_link_libraries(program_qt_gpp_cmake PRIVATE
    Qt6::Widgets
)

set_target_properties(program_qt_gpp_cmake PROPERTIES
    WIN32_EXECUTABLE ON
)

My build.bat script is this:

cmake --build . --config Debug --target program_qt_gpp_cmake

So, I proceed as follows:

Why do I get this error? Where is qMain defined and what else should I link (I'm already using Qt6 in the CMakeLists.txt)?


Solution

  • The source of the problem is that the Qt's Windows-specific entrypoint lib expects main to have the signature int main(int, char**). Curiously, when compiling with msvc, int main() seems to work. (qMain enters the equation only for mingw32 builds, as far as I know. This might explain this phenomenon.)

    Some background: for mingw32 builds, #define main qMain will "mask" main by renaming it to qMain. qMain is declared as int qMain(int, char **);. Therefore main must have signature int main(int, char**).