当前位置: 首页 > news >正文

Qt6-学习Cmakelist(翻译官方文档)

用 CMake 开始 Qt 6 开发:从控制台到 GUI 应用的完整指南

CMake 是一套强大的工具集,能帮助我们构建、测试和打包应用程序。和 Qt 一样,它支持所有主流开发平台,并且被包括 Qt Creator 在内的多种 IDE 所支持。本文将带你一步步了解如何在 Qt 6 项目中使用 CMake,从简单的控制台应用到复杂的 GUI 程序,再到项目结构优化和资源管理,全方位掌握 CMake 与 Qt 的结合使用。

构建 C++ 控制台应用

CMake 项目由 CMake 语言编写的文件定义,其中主文件名为 CMakeLists.txt,通常与程序源代码放在同一目录下。

下面是一个使用 Qt 的 C++ 控制台应用的典型 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.16)project(helloworld VERSION 1.0.0 LANGUAGES CXX)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(Qt6 REQUIRED COMPONENTS Core)
qt_standard_project_setup()qt_add_executable(helloworldmain.cpp
)target_link_libraries(helloworld PRIVATE Qt6::Core)

让我们逐行解析这段代码的含义:

  1. 指定最低 CMake 版本

    cmake_minimum_required(VERSION 3.16)
    

    这行命令指定了配置项目所需的最低 CMake 版本。Qt 对 CMake 版本有特定要求,你可以查看支持的 CMake 版本了解详情。

  2. 设置项目信息

    project(helloworld VERSION 1.0.0 LANGUAGES CXX)
    

    project() 命令设置了项目名称(helloworld)和默认版本(1.0.0)。LANGUAGES CXX 表明该程序使用 C++ 编写。

  3. 配置 C++ 标准

    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    

    Qt 6 要求编译器支持 C++ 17 或更高版本。通过设置这两个变量,CMake 会在编译器版本过低时报错提醒。

  4. 查找 Qt 模块

    find_package(Qt6 REQUIRED COMPONENTS Core)
    

    这行命令告诉 CMake 查找 Qt 6 并加载 Core 模块。REQUIRED 标志表示如果找不到该模块,CMake 会终止配置过程。成功后,会导入 Qt6::Core 目标供后续使用。更多信息可以参考在 CMake 项目中使用 Qt。

  5. Qt 标准项目设置

    qt_standard_project_setup()
    

    这个命令为典型的 Qt 应用设置了项目级别的默认配置,其中包括将 CMAKE_AUTOMOC 设为 ON,这样 CMake 会自动处理 Qt 的元对象编译器(moc)的调用规则。你可以查看qt_standard_project_setup的参考文档了解更多细节。

  6. 创建可执行目标

    qt_add_executable(helloworldmain.cpp
    )
    

    qt_add_executable() 命令告诉 CMake 我们要构建一个名为 helloworld 的可执行文件。它是 CMake 内置的 add_executable() 命令的封装,提供了额外的逻辑来处理静态 Qt 构建中的插件链接、库名的平台特定定制等问题。

    注意,这里通常不需要列出头文件,这与 qmake 不同——在 qmake 中,头文件需要显式列出以便 moc 处理。如果要创建库,可以使用 qt_add_library 命令。

  7. 链接 Qt 库

    target_link_libraries(helloworld PRIVATE Qt6::Core)
    

    最后,target_link_libraries 告诉 CMake,helloworld 可执行文件使用了 Qt Core 模块,通过引用前面 find_package() 导入的 Qt6::Core 目标来实现。这不仅会添加正确的链接参数,还会确保编译器获得正确的包含目录和定义。对于可执行目标,PRIVATE 关键字不是必须的,但作为最佳实践建议加上。如果是库目标,则需要根据情况指定 PRIVATEPUBLIC(如果库的头文件中使用了 Qt6::Core 的内容,则用 PUBLIC,否则用 PRIVATE)。

构建 C++ GUI 应用

在前面的部分,我们展示了控制台应用的 CMakeLists.txt 文件。现在,我们将扩展它,创建一个使用 Qt Widgets 模块的 GUI 应用:

cmake_minimum_required(VERSION 3.16)project(helloworld VERSION 1.0.0 LANGUAGES CXX)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(Qt6 REQUIRED COMPONENTS Widgets)
qt_standard_project_setup()qt_add_executable(helloworldmainwindow.uimainwindow.cppmain.cpp
)target_link_libraries(helloworld PRIVATE Qt6::Widgets)set_target_properties(helloworld PROPERTIESWIN32_EXECUTABLE ONMACOSX_BUNDLE ON
)

让我们看看这些变化:

  1. 更换 Qt 模块

    find_package(Qt6 REQUIRED COMPONENTS Widgets)
    

    find_package 调用中,我们将 Core 替换为 Widgets,这样会加载 Qt6Widgets 模块并提供 Qt6::Widgets 目标。注意,由于 Qt6::Widgets 依赖于 Qt6::Core,应用仍然会链接到 Core 模块。

  2. 自动处理 UI 文件

    qt_standard_project_setup()
    

    除了 CMAKE_AUTOMOC,这个命令还会将 CMAKE_AUTOUIC 设为 ON,从而自动创建规则来调用 Qt 的用户界面编译器(uic)处理 .ui 源文件。

  3. 添加 UI 相关文件

    qt_add_executable(helloworldmainwindow.uimainwindow.cppmain.cpp
    )
    

    我们在应用目标的源文件中添加了一个 Qt Widgets 设计器文件(mainwindow.ui)及其对应的 C++ 源文件(mainwindow.cpp)。

    注意:另一种添加 .ui 文件的方法是使用 qt_add_ui 命令,而不是依赖 AUTOUIC

  4. 链接 Widgets 库

    target_link_libraries(helloworld PRIVATE Qt6::Widgets)
    

    这里我们将链接目标改为 Qt6::Widgets,替代了之前的 Qt6::Core

  5. 设置目标属性

    set_target_properties(helloworld PROPERTIESWIN32_EXECUTABLE ONMACOSX_BUNDLE ON
    )
    

    这些属性设置的作用是:

    • 在 Windows 上避免创建控制台窗口
    • 在 macOS 上创建应用程序包

    你可以查看CMake 文档了解更多关于这些目标属性的信息。

项目结构组织

对于包含多个目标的项目,清晰的项目文件结构会让开发更高效。我们可以利用 CMake 的子目录功能来实现。

当计划扩展项目添加更多目标时,我们可以将应用的源文件移动到子目录中,并在那里创建新的 CMakeLists.txt

<项目根目录>
├── CMakeLists.txt
└── src└── app├── CMakeLists.txt├── main.cpp├── mainwindow.cpp├── mainwindow.h└── mainwindow.ui

顶层的 CMakeLists.txt 包含整体的项目设置、find_packageadd_subdirectory 调用:

cmake_minimum_required(VERSION 3.16)project(helloworld VERSION 1.0.0 LANGUAGES CXX)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(Qt6 REQUIRED COMPONENTS Widgets)
qt_standard_project_setup()add_subdirectory(src/app)

在这个文件中设置的变量在子目录的项目文件中也可见。

应用的项目文件 src/app/CMakeLists.txt 则包含可执行目标的定义:

qt_add_executable(helloworldmainwindow.uimainwindow.cppmain.cpp
)target_link_libraries(helloworld PRIVATE Qt6::Widgets)set_target_properties(helloworld PROPERTIESWIN32_EXECUTABLE ONMACOSX_BUNDLE ON
)

这种结构便于添加更多目标,如库或单元测试。

注意:建议将项目的构建目录添加到系统上运行的任何杀毒软件的排除目录列表中,以避免不必要的干扰。

构建库

随着项目增长,你可能希望将部分应用代码抽离为库,供应用程序和单元测试使用。本节将展示如何创建这样的库。

假设我们的应用程序目前在 main.cpp 中包含业务逻辑,我们将这部分代码提取到一个名为 businesslogic 的静态库中,放在 src/businesslogic 子目录下(如前一节所述的结构)。

为简单起见,这个库只包含一个 C++ 源文件和对应的头文件,供应用的 main.cpp 包含:

<项目根目录>
├── CMakeLists.txt
└── src├── app│   ├── ...│   └── main.cpp└── businesslogic├── CMakeLists.txt├── businesslogic.cpp└── businesslogic.h

让我们看看这个库的项目文件(src/businesslogic/CMakeLists.txt):

qt_add_library(businesslogic STATICbusinesslogic.cpp
)
target_link_libraries(businesslogic PRIVATE Qt6::Core)
target_include_directories(businesslogic INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

逐行解析如下:

  1. 创建库目标

    qt_add_library(businesslogic STATICbusinesslogic.cpp
    )
    

    qt_add_library 命令创建了名为 businesslogic 的库。STATIC 关键字表示这是一个静态库,如果要创建共享库或动态库,可以使用 SHARED 关键字。之后,我们会让应用程序链接到这个目标。

  2. 链接 Qt 核心库

    target_link_libraries(businesslogic PRIVATE Qt6::Core)
    

    虽然静态库实际上不需要链接其他库,但由于我们的库使用了 QtCore 中的类,添加对 Qt6::Core 的链接依赖可以引入必要的 QtCore 包含路径和预处理器定义。

  3. 设置包含目录

    target_include_directories(businesslogic INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
    

    库的 API 在头文件 businesslogic/businesslogic.h 中定义。通过调用 target_include_directories,我们确保所有使用这个库的目标(应用程序)都会自动将 businesslogic 目录的绝对路径添加到包含路径中。

    这样,在 main.cpp 中就不需要使用相对路径来引用 businesslogic.h 了,只需简单地写:

    #include <businesslogic.h>
    

最后,我们需要将库的子目录添加到顶层项目文件中:

add_subdirectory(src/app)
add_subdirectory(src/businesslogic)

使用库

要使用上一节创建的库,我们需要告诉 CMake 链接到它:

target_link_libraries(helloworld PRIVATEbusinesslogicQt6::Widgets
)

这确保了编译 main.cpp 时能找到 businesslogic.h,并且 businesslogic 静态库会被包含到 helloworld 可执行文件中。

在 CMake 中,businesslogic 库指定了「使用要求」(即包含路径),所有使用该库的目标(应用程序)都需要满足这些要求,target_link_libraries 命令会自动处理这一点。

添加资源

如果我们想在应用程序中显示图片,可以使用Qt 资源系统来添加它们:

qt_add_resources(helloworld imageresourcesPREFIX "/images"FILES logo.png splashscreen.png
)

qt_add_resources() 命令会自动创建一个包含指定图片的 Qt 资源。在 C++ 源代码中,可以通过指定的资源前缀来访问这些图片:

logoLabel->setPixmap(QPixmap(":/images/logo.png"));

qt_add_resources() 命令的第一个参数可以是变量名或目标名。我们建议使用如示例中所示的基于目标的方式。

添加翻译

Qt 项目中的字符串翻译存储在 .ts 文件中,这些文件会被编译为二进制的 .qm 文件,供 Qt 应用程序在运行时加载。详情请参见Qt 国际化。

本节将描述如何为 helloworld 应用添加德语和法语翻译。

首先,在 qt_standard_project_setup 中指定这两种语言:

qt_standard_project_setup(I18N_TRANSLATED_LANGUAGES de fr)

然后,对需要加载 .qm 文件的目标调用 qt_add_translations

qt_add_translations(helloworld)

在第一次配置时,这个命令会在项目的源目录中创建 helloworld_de.tshelloworld_fr.ts 文件,这些文件包含翻译后的字符串,应该纳入版本控制。

该命令还会创建构建系统规则,自动从 .ts 文件生成 .qm 文件。默认情况下,.qm 文件会嵌入到资源中,可通过 "/i18n" 资源前缀访问。

要更新 .ts 文件中的条目,可以构建 update_translations 目标:

$ cmake --build . --target update_translations

要手动触发 .qm 文件的生成,可以构建 release_translations 目标:

$ cmake --build . --target release_translations

关于如何影响 .ts 文件的处理和资源嵌入方式的更多信息,请参见qt_add_translations 文档。

qt_add_translations 是一个便捷的封装命令。如果需要更精细地控制 .ts 文件和 .qm 文件的处理,可以使用底层命令 qt_add_lupdateqt_add_lrelease

http://www.dtcms.com/a/284876.html

相关文章:

  • Pytorch深度学习框架实战教程02:开发环境部署
  • python学智能算法(二十二)|SVM-点与超平面的距离
  • faster-lio仿真环境问题及解决
  • 腾讯云服务上下载docker以及使用Rabbitmq的流程
  • Python网络爬虫——介绍
  • 【unitrix】 6.5 基础整数类型特征(base_int.rs)
  • Redis:哨兵(Sentinel)
  • MySQL的索引操作及底层结构浅析
  • 产品经理如何描述用户故事
  • modelscope ProxyError: HTTPSConnectionPool(host=‘www.modelscope.cn‘, port=443)
  • 作物长势产量预测yyds!遥感数据同化DSSAT模型,区域精准农业就靠它!
  • 27、鸿蒙Harmony Next开发:ArkTS并发(Promise和async/await和多线程并发TaskPool和Worker的使用)
  • Hyperledger Fabric:构建企业区块链网络的实践指南
  • 【实时Linux实战系列】硬件中断与实时性
  • 什么是GEO 和 SEO ?GEO 与 SEO 有什么区别?如何快速入门GEO?
  • 解决宝塔面板SSL报错 - AttributeError: module ‘acme_v2‘ has no attribute ‘acme_v2‘
  • 搜广推校招面经九十四
  • 神经网络构建
  • STM32之土壤湿度传感器模块
  • Toward the unification of kselftests and KUnit
  • MYSQL-进阶-锁
  • 离散与组合数学 杂记
  • 电子制造企业排产优化实战:用JVS智能排产的排产策略实现交期100%可控
  • OCR 与 Agent:智能协作的 “黄金搭档”
  • Spring Boot整合阿里云OSS:企业级文件存储最佳实践
  • ZYNQ UltraScale+ MPSoC芯片 pcie switch级联ssd高速存储方案
  • 基于springboot+vue+mysql平台的医疗病历交互系统(源码+论文)
  • 解析:视频创作中常见版权问题
  • JAVA原生实现SOAP POST调用
  • 【深度学习】神经网络过拟合与欠拟合-part5