QtCreator compiles GUI programs with CMake under Windows

1, Foreword

Why use CMake to build Qt projects? Does Qt have qmake? Isn't that unnecessary?
In fact, it is very necessary to use CMake to build a project, especially when your project involves many third-party libraries, the advantages of CMake are very prominent.

Qt5.15.2 when selecting the installation module before, CMake was automatically checked for us_ 64 module, you can also choose to check CMake_32 module, so QtCreator supports CMake compilation, not only QMake compilation.

I also manually installed cmake3 Version 20.0, which can be seen in the cmake item of suite configuration in QtCreator:


Let's introduce two methods of Qt compiling using CMake.


2, Rely on QtCreator to automatically generate cmakelists Txt file

When QtCreator creates a new project, select cmake instead of the default qmake compilation method, as shown below:


Then choose which compilation suite CMake will compile into, MingW or MSVC. Qt5 is selected here 15.2 MingW 64, after successful creation and operation:


You can see that QtCreator automatically helps generate cmakelists Txt file, which can be used directly. Its contents are as follows:

cmake_minimum_required(VERSION 3.5)

project(HelloWorld 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 https://doc.qt.io/qt/deployment-android.html for more information.
# They need to be set before the find_package( ...) calls below.

#if(ANDROID)
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
#    if (ANDROID_ABI STREQUAL "armeabi-v7a")
#        set(ANDROID_EXTRA_LIBS
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
#    endif()
#endif()

find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)

set(PROJECT_SOURCES
        main.cpp
        widget.cpp
        widget.h
        widget.ui
)

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(HelloWorld
        ${PROJECT_SOURCES}
    )
else()
    if(ANDROID)
        add_library(HelloWorld SHARED
            ${PROJECT_SOURCES}
        )
    else()
        add_executable(HelloWorld
            ${PROJECT_SOURCES}
        )
    endif()
endif()

target_link_libraries(HelloWorld PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)

QtCreator also helps add CMake Modules to support Qt5Core, Qt5Gui and other modules.

Other classes, such as Form, will not be automatically added to cmakelists Txt file, which needs to be added manually:

set(PROJECT_SOURCES
        main.cpp
        widget.cpp
        widget.h
        widget.ui
        #Here is the manual addition
        form.cpp
        form.h
        form.ui
)

Additional modules need to be added, similarly.

Of course, automatically generated cmakelists Txt some cumbersome contents, such as the configuration of ANDROID. The following will introduce how to write cmakelists by yourself Txt to create a project.


3, Manually configure cmakelists txt

You can also manually configure cmakelists txt.

First, we will use QtCreator to create the project: helloworld. The list of files in the project is as follows: Although the project is small, it has all the internal organs, and all the necessary files (. H. CPP. qrc. UI. Pro. png). I'll take it png files and The qrc file is placed in a new resources folder.

├── helloworld.pro
├── helloworld.pro.user
├── main.cpp
├── resources
│   ├── ico.png
│   └── resources.qrc
├── widget.cpp
├── widget.h
└── widget.ui

The only place in the project where you need to add code is the widget Cpp file, because we need to add an icon:

#include "widget.h"
#include "ui_widget.h"
#include <QIcon>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // Form title
    this->setWindowTitle("Qt5.1 Form Application ");
    // Form ICO picture, such as the picture can not afford alias, suffix directly write the full name of the picture.
    this->setWindowIcon(QIcon(":/new/prefix1/ico.png"));
}

Widget::~Widget()
{
    delete ui;
}

Next, manually create a cmakelists in the project folder Txt file, which is added to the project. Its contents are as follows:

#Set cmake version number
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)

#Set the project name (modify as appropriate)
project(helloworld)

# Add C++11 (not required)
set(CMAKE_CXX_STANDARD 11)

#Open global moc
set(CMAKE_AUTOMOC ON)
#Open global uic
set(CMAKE_AUTOUIC ON)
#Open global rcc. If qrc is not used, this sentence can be removed
set(CMAKE_AUTORCC ON)

#Set the project to include the current directory, using * ui file, you need to add this sentence, otherwise the header file cannot be found
set(CMAKE_INCLUDE_CURRENT_DIR ON)

#Find the required Qt library files. It is best to write each library, and QT will be automatically added according to the dependency
find_package(Qt5 REQUIRED Widgets)

#Create project file
add_executable(helloworld main.cpp widget.cpp widget.h widget.ui resources/resources.qrc)

#Add Qt5 dependency
target_link_libraries(helloworld Qt5::Widgets)

This is cmakelists Txt write the first method, global control: from CMake global control file generation, very simple! Two other methods will be introduced later.

The final project composition is as follows:

├── CMakeLists.txt
├── CMakeLists.txt.user
├── helloworld.pro
├── helloworld.pro.user
├── main.cpp
├── resources
│   ├── ico.png
│   └── resources.qrc
├── widget.cpp
├── widget.h
└── widget.ui

Close the helloworld project you created before, and then use QtCreator to directly open cmakelists Txt file, a configure window will pop up at the beginning. You can configure the project directly, and then cmake the project and add main cpp,widget.h and other source files into the project. Finally, build and run the project and report an error:

F:\Project\CMake\helloworld\widget.cpp:-1: error: undefined reference to `vtable for Widget'

In the online search, it is found that it is related to the moc mechanism of Qt, that is, the "meta object compiler", which is related to the macro Q that needs to be defined_ Object, and cmakelists Txt. The solution is to annotate the macro Q_OBJECT.

The full name of moc is meta object compiler, or "meta object compiler". Before the Qt program is compiled by the standard compiler, the C + + source file must be analyzed by moc. If it finds that a macro q is included in a header file_ Object, another C + + source file will be generated. This source file contains Q_ Implementation code of object macro

After modification, it runs successfully, as shown in the following figure:


4, Extension: cmakelists Txt prepared by the other two methods

Cmakelists is described above Txt write the first method, global control, the following describes the other two methods.


Method 2: target control

#Set cmake version number
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)

#Set the project name (modify as appropriate)
set(project_name helloworld)
project(${project_name})

# Add C++11 (not required)
set(CMAKE_CXX_STANDARD 11)

#Find the required Qt library files. It is best to write each library, and QT will be automatically added according to the dependency
find_package(Qt5 REQUIRED Widgets)

#Set target name
set(target_name ${project_name})
#Create project file
add_executable(${target_name} main.cpp widget.cpp widget.h widget.ui resources/resources.qrc)
#Add Qt5 dependency
target_link_libraries(${target_name} Qt5::Widgets)

#Set target associated * h, *.cpp is compiled using Qt moc
set_target_properties(${target_name} PROPERTIES AUTOMOC ON)
#Set target associated * The ui is compiled using Qt uic
set_target_properties(${target_name} PROPERTIES AUTOUIC ON)
#Associated target settings * qrc is compiled using Qt uic
set_target_properties(${target_name} PROPERTIES AUTORCC ON)

#Skip files that do not need to be compiled using moc. If you feel troublesome, you can not write this sentence. automoc can write it according to * h,*. Macros in CPP code (Q_OBJECT;Q_GADGET;Q_NAMESPACE) automatically determine whether moc is required
set_source_files_properties(main.cpp PROPERTIES SKIP_AUTOMOC ON)

Using this method, the file generation is controlled from the target (executable or library), and the controllable strength is more detailed.

The above two methods:

The VS project generated by CMake's official Auto method will be modified in three places:

  • Will put a mocs_compilation.cpp added to the project
  • A sentence "testwindow" will be added in the [attachment containing path]_ autogen\include_ xxx
  • A preprocessing command will be added in [pre generation event], and the MOC will be automatically regenerated after the source file is modified_ xxx. Cpp file

Method III. single document control

#Set cmake version number
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)

#Set the project name (modify as appropriate)
set(project_name helloworld)
project(${project_name})

# Add C++11 (not required)
set(CMAKE_CXX_STANDARD 11)

#Find the required Qt library files. It is best to write each library, and QT will be automatically added according to the dependency
find_package(Qt5 REQUIRED Widgets)

#Contains the current path, using * ui file, you need to add this sentence, otherwise the header file cannot be found
set(CMAKE_INCLUDE_CURRENT_DIR ON)

#The moc file that needs to be generated. The name of the output file is placed in the variable mocfiles. It can only be called in find QT5 package
qt5_wrap_cpp(mocfiles widget.h)
source_group("moc" FILES ${mocfiles})

#The ui file to be generated can only be called in find QT5 package
qt5_wrap_ui(uifiles widget.ui)

#Open global rcc. If qrc is not used, this sentence can be removed
set(CMAKE_AUTORCC ON)

#Set target name
set(target_name ${project_name})
#Add the generated moc file to the target
add_executable(${target_name} main.cpp widget.cpp widget.h widget.ui resources/resources.qrc ${mocfiles})
target_link_libraries(${target_name} Qt5::Widgets)

This method starts from the source file to control the file generation, which is a little troublesome.

After CMake generates the VS project, MainWindow The preprocessing command of UI is placed in MainWindow UI attribute configuration, while MainWindow The preprocessing command of H is placed in CMake Rules/moc_mainwindow.cpp.rule attribute configuration. After the source file is modified, the target file will be generated automatically.


reference resources:

Using cmake to build QT 5.0-based 8.0 qt5 items

Summary of Qt+CMake solutions and problems

Building Qt5 project with CMake

Original]Qt Creator builds CMake project

CMake tutorial - QT project uses CMake

CMake learning (1) - installation and use under Windows


Tags: cmake

Posted by anto on Thu, 14 Apr 2022 21:09:19 +0930