打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Windows下QtCreator使用CMake编译GUI程序
摘要:

Qt5.15.2在之前选择安装模块的时候,自动帮我们勾选了CMake_64模块,你也可以另外选择勾选CMake_32模块,所以QtCreator是支持CMake编译方式的,而不仅仅只能使用QMake编译。本人之前也手动安装了CMake3.20.0的版本,这些可以在QtCreator中的套件配置的cmake项看到:下面我们介绍一下Qt使用CMake编译的两种方式。首先,我们还是要使用QtCreator创建项目:helloworld。

<< 收起

一、前言

为什么要用 CMake 来构建 Qt 的项目呢?Qt 不是有 qmake 吗?这样,岂不是多此一举?
其实,应用 CMake 来构建项目还是非常有必要的,特别是当你的项目涉及到很多第三方库的时候,CMake 的优势非常突出。

Qt5.15.2 在之前选择安装模块的时候,自动帮我们勾选了 CMake_64 模块,你也可以另外选择勾选 CMake_32 模块,所以 QtCreator 是支持 CMake 编译方式的,而不仅仅只能使用 QMake 编译。

本人之前也手动安装了 CMake3.20.0 的版本,这些可以在 QtCreator 中的套件配置的 cmake 项看到:


下面我们介绍一下 Qt 使用 CMake 编译的两种方式。


二、依赖QtCreator自动生成CMakeLists.txt文件

QtCreator 新建工程时,选择 cmake 而不是默认的 qmake 编译方式,如下所示:


然后选择 CMake 要编译成的哪种编译套件,是 MingW 还是 MSVC,这里选择的是 Qt5.15.2 MinGW 64,创建运行成功后:


可以看到 QtCreator 自动帮忙生成了 CMakeLists.txt 文件,直接可以使用,其内容如下:

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 也帮忙添加了 CMake Modules,来支持对 Qt5Core、Qt5Gui 等模块的支持。

就是后续在工程中添加其它的类,比如 Form 类,不会自动添加到 CMakeLists.txt 文件中,需要手动添加:

set(PROJECT_SOURCES
        main.cpp
        widget.cpp
        widget.h
        widget.ui
        #下面为手动添加内容
        form.cpp
        form.h
        form.ui
)

需要添加额外的模块,同理。

当然自动生成的 CMakeLists.txt 有些累赘的内容,比如对 ANDROID 的配置,下面会介绍一下如何自己编写 CMakeLists.txt 来创建工程。


三、手动配置CMakeLists.txt

你也可以自己手动配置 CMakeLists.txt。

首先,我们还是要使用 QtCreator 创建项目:helloworld。项目中的文件列表如下:项目虽小,五脏俱全,该有的文件都有了(.h .cpp .qrc .ui .pro .png)。我把 .png 文件和 .qrc 文件放在了一个新建的 resources 资源文件夹中。

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

该项目中唯一需要添加代码的地方是 widget.cpp 文件,因为我们需要添加一个图标:

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 窗体标题
    this->setWindowTitle("Qt5.1 窗体应用");
    // 窗体 ICO 图片,如图不起别名,后缀直接写图片全名。
    this->setWindowIcon(QIcon(":/new/prefix1/ico.png"));
}

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

接着在项目文件夹中手动创建一个 CMakeLists.txt 文件,添加到工程中,其内容如下:

#设置cmake版本号
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)

#设置工程名称(看情况修改)
project(helloworld)

# 添加C++11(非必须)
set(CMAKE_CXX_STANDARD 11)

#打开全局moc
set(CMAKE_AUTOMOC ON)
#打开全局uic
set(CMAKE_AUTOUIC ON)
#打开全局rcc,如果没有使用qrc,此句可以去掉
set(CMAKE_AUTORCC ON)

#设置工程包含当前目录,使用*.ui文件时,需要加上这句,否则找不到头文件
set(CMAKE_INCLUDE_CURRENT_DIR ON)

#查找需要的Qt库文件,最好每一个库都要写,Qt也会根据依赖关系自动添加
find_package(Qt5 REQUIRED Widgets)

#创建工程文件
add_executable(helloworld main.cpp widget.cpp widget.h widget.ui resources/resources.qrc)

#添加Qt5依赖项
target_link_libraries(helloworld Qt5::Widgets)

这是 CMakeLists.txt 编写的第一种方法,全局控制:从 CMake 全局入手控制文件生成,非常简便!后面会介绍另外两种方法。

最后的项目组成如下:

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

关闭之前创建的 helloworld 项目,然后用 QtCreator 直接打开 CMakeLists.txt 文件,一开始会弹出一个 configure 窗口,直接 configure 就可以实现项目配置,然后 cmake 该工程,就会添加 main.cpp、widget.h 等源文件到工程中。最后构建运行该项目报错:

F:ProjectCMakehelloworldwidget.cpp:-1: error: undefined reference to `vtable for Widget'

在网上搜索发现,跟 Qt 的 moc 机制有关,也就是“元对象编译器”,与之相关需要定义的宏 Q_OBJECT,与 CMakeLists.txt 中的set(CMAKE_AUTOMOC ON)冲突,解决办法就是注释宏 Q_OBJECT。

moc 全称是 Meta-Object Compiler,也就是“元对象编译器”。Qt 程序在交由标准编译器编译之前,先要使用 moc 分析 C++ 源文件。如果它发现在一个头文件中包含了宏 Q_OBJECT,则会生成另外一个 C++ 源文件。这个源文件中包含了 Q_OBJECT 宏的实现代码

修改后运行成功,如下图所示:


四、扩展:CMakeLists.txt 编写的另外两种方法

上面介绍了 CMakeLists.txt 编写的第一种方法,全局控制,下面介绍另两种方法。


方法二、目标控制

#设置cmake版本号
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)

#设置工程名称(看情况修改)
set(project_name helloworld)
project(${project_name})

# 添加C++11(非必须)
set(CMAKE_CXX_STANDARD 11)

#查找需要的Qt库文件,最好每一个库都要写,Qt也会根据依赖关系自动添加
find_package(Qt5 REQUIRED Widgets)

#设置目标名称
set(target_name ${project_name})
#创建工程文件
add_executable(${target_name} main.cpp widget.cpp widget.h widget.ui resources/resources.qrc)
#添加Qt5依赖项
target_link_libraries(${target_name} Qt5::Widgets)

#设置目标关联的*.h, *.cpp 使用 Qt moc进行编译
set_target_properties(${target_name} PROPERTIES AUTOMOC ON)
#设置目标关联的*.ui 使用 Qt uic进行编译
set_target_properties(${target_name} PROPERTIES AUTOUIC ON)
#设置目标关联的*.qrc 使用 Qt uic进行编译
set_target_properties(${target_name} PROPERTIES AUTORCC ON)

#跳过不需要使用moc编译的文件。如果觉得麻烦此句可以不写,automoc能根据*.h,*.cpp代码里面的宏(Q_OBJECT;Q_GADGET;Q_NAMESPACE)自动判断是否需要使用moc
set_source_files_properties(main.cpp PROPERTIES SKIP_AUTOMOC ON)

使用该方法,从目标(可执行或者库)入手控制文件生成,可控力度更细一些。

上述两种方法:

使用 CMake 官方 Auto 方法生成的 VS 工程,主要会修改三个地方:

  • 会将一个 mocs_compilation.cpp 添加到工程里面
  • 【附件包含路径】中会添加一句TestWindow_autogeninclude_xxx
  • 【预先生成事件】中会添加预处理命令,源文件修改后会自动重新生成 moc_xxx.cpp 文件

方法三、单个文件控制

#设置cmake版本号
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)

#设置工程名称(看情况修改)
set(project_name helloworld)
project(${project_name})

# 添加C++11(非必须)
set(CMAKE_CXX_STANDARD 11)

#查找需要的Qt库文件,最好每一个库都要写,Qt也会根据依赖关系自动添加
find_package(Qt5 REQUIRED Widgets)

#包含当前路径,使用*.ui文件时,需要加上这句,否则找不到头文件
set(CMAKE_INCLUDE_CURRENT_DIR ON)

#需要生成的moc文件,输出文件名称放在变量 mocfiles中,必须在find QT5 package才能调用
qt5_wrap_cpp(mocfiles widget.h)
source_group("moc" FILES ${mocfiles})

#需要生成的ui文件,必须在find QT5 package才能调用
qt5_wrap_ui(uifiles widget.ui)

#打开全局rcc,如果没有使用qrc,此句可以去掉
set(CMAKE_AUTORCC ON)

#设置目标名称
set(target_name ${project_name})
#添加生成的moc文件到目标中
add_executable(${target_name} main.cpp widget.cpp widget.h widget.ui resources/resources.qrc ${mocfiles})
target_link_libraries(${target_name} Qt5::Widgets)

该方法从 源文件 入手控制文件生成,要稍微麻烦一些。

CMake 生成 VS 工程后,将 mainwindow.ui 的预处理命令放在 mainwindow.ui 属性配置中,而 mainwindow.h 的预处理命令放在CMake Rules/moc_mainwindow.cpp.rule的属性配置中。源文件修改后,目标文件会自动生成。


参考:

用cmake构建基于qt5.8.0的qt5项目

Qt+CMake解决方案及问题汇总

使用CMake构建Qt5工程

原创]Qt Creator构建CMake项目

CMake教程——QT项目使用CMake

CMake学习(1)-Windows下安装与使用


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
QtCreator之cmake项目创建编译流程
Qt Creator 根据已有的CMakeList.txt创建CMake工程
cmake与qmake
cmake在Windows上的使用
Qt5中使用CMake(Qt5.9.3)
CMake 备忘清单
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服