QGC4.3.0源码学习 - 阅读顶层CMakeLists.txt(3)

本文详细解释了CMake在Qt项目中的使用,包括启用AUTOMOC、AUTOUIC和AUTORCC自动编译功能,CMAKE_INCLUDE_CURRENT_DIR的作用,以及如何通过find_package管理和配置Qt组件,如设置QT_VERSION和Qt6库路径等。
摘要由CSDN通过智能技术生成

Qt AUTOMOC元对象编译

Qt 程序在交由标准编译器编译之前,先要使用 moc(meta-object compiler) 分析 C++ 源文件,将信号/槽等Qt特有的特性,用标准C++实现,产生标准的源文件。

CMake有专门的命令启用此过程,QGC顶层CMakeLists.txt有如下语句:

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

以上命令参考CMake官方文档:

AUTOMOC — CMake 3.29.2 Documentation

AUTOMOC是一个布尔值,指定 CMake是否会自动将有Qt moc特性的源文件转化为标准c++源文件。

AUTOUIC是一个布尔值,指定CMake是否会自动将Qt .ui文件转化为C++源文件。

AUTORCC是一个布尔值,指定CMake是否会自动根据Qt .qrc资源文件(xml格式),查找指定资源(图片、字体…),将这些资源编译为二进制数据添加到应用程序。

CMAKE_INCLUDE_CURRENT_DIR

QGC顶层CMakeLists.txt中有一句命令:

set(CMAKE_INCLUDE_CURRENT_DIR OFF)

 CMake官方文档(CMAKE_INCLUDE_CURRENT_DIR — CMake 3.29.2 Documentation)针对CMAKE_INCLUDE_CURRENT_DIR变量有说明:

如果启用此变量,CMake会自动将CMAKE_CURRENT_SOURCE_DIR和CMAKE_CURRENT_BINARY_DIR添加到每个目录的包含路径中。

CMAKE_CURRENT_SOURCE_DIR是指当前处理CMakeLists.txt所在的目录

CMAKE_CURRENT_BINARY_DIR是指build之后产生的xxx-Debug或者xxx-Release目录。

此处设置为OFF,不会自动包含${CMAKE_CURRENT_SOURCE_DIR}和${CMAKE_CURRENT_BINARY_DIR}。

CMAKE_MODULE_PATH

参考官方文档(CMAKE_MODULE_PATH — CMake 3.29.2 Documentation)

调用include或者find_package搜索.cmake文件,首先在${CMAKE_MODULE_PATCH}进行搜索,没找到再去CMake自带的安装目录下的module目录下搜索。

CMAKE_MODULE_PATCH是一个list,通过list(APPEND CMAKE_MODULE_PATH xxx)添加本地的cmake模块目录。

QGC顶层CMakeLists.txt有如下语句:

list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)

目的是添加顶层CMakeLists.txt同级的cmake目录,为搜索目录:

内部有如下.cmake文件:

cmake_print_variables

QGC顶层CMakeLists.txt在include (CMakePrintHelpers)之后,调用cmake_print_variables完成多个CMAKE标准变量的打印,用于cmake调试:

cmake_print_variables(CMAKE_VERSION)
cmake_print_variables(CMAKE_PREFIX_PATH)
cmake_print_variables(CMAKE_HOST_SYSTEM_NAME)
cmake_print_variables(CMAKE_HOST_SYSTEM_VERSION)
cmake_print_variables(CMAKE_SYSTEM_NAME)
cmake_print_variables(CMAKE_SYSTEM_VERSION)
cmake_print_variables(CMAKE_CURRENT_SOURCE_DIR)
cmake_print_variables(CMAKE_BUILD_TYPE)
cmake_print_variables(CMAKE_TOOLCHAIN_FILE)

也可用message(STATUS ${ CMAKE_VERSION })去打印,不过cmake_print_variables是新语法,更加推荐。

Qt6 Configuration

在前文添加.cmake搜索路径之后:

list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)

此处include(Qt6QGCConfiguration),将会在cmake目录下搜索到。Qt6QGCConfiguration.cmake文件并执行,查看此文件得到其内容如下:

如果本机设置了QT_VERSION环境变量,在当前.cmake文件内设置QT_VERSION变量为$ENV{QT_VERSION};如果本机没有设置QT_VERSION环境变量,搜索本机下$ENV{HOME}/Qt/6.6.*的目录,放到FOUND_QT_VERSION变量中(list),根据HOME环境变量去搜索,可以在powershell输入:$Env:HOME得到具体的路径。

在获得FOUND_QT_VERSION之后,调用

list(GET FOUND_QT_VERSION 0 QT_VERSION_PATH)

获得QT_VERSION的路径,存储到变量QT_VERSION_PATH中。调用get_file_component获得QT版本信息存储到QT_VERSION变量。

get_filename_component(QT_VERSION ${QT_VERSION_PATH} NAME)

总之,第一步获取QT version信息,存储到QT_VERSION变量;

第二步获取QT的make类型,存储到QT_MKSPEC变量,主要有clang_64(apple)、gcc_64(linux)、msvc2019(win32)、armxxx(android);

第三步设置QT_LIBRARY_HINTS变量,存储Qt6库文件地址

如果是android平台还有:

if(ANDROID)
	list(APPEND QT_LIBRARY_HINTS ${QT_HOST_PATH}/lib/cmake)
elseif(WIN32)
	list(APPEND QT_LIBRARY_HINTS C:/Qt/${QT_VERSION}/${QT_MKSPEC})
elseif(LINUX)
	list(APPEND QT_LIBRARY_HINTS $ENV{HOME}/Qt/${QT_VERSION}/${QT_MKSPEC})
endif()

总结include(Qt6QGCConfiguration)作用是:设置QT_LIBRARY_HINTS变量,此变量在find_package作为HINTS使用,指示应用程序在搜索Qt6组件的路径。

设置QML输出目录

设置QML输出目录,并存储到cache变量QT_QML_OUTPUT_DIRECTORY

set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml" CACHE PATH "Install path for QML" FORCE)

 参考qt官方文档:QT_QML_OUTPUT_DIRECTORY | Qt QML 6.7.1

设置Qt最低版本

参考官方文档Porting to Qt 6 | Qt 6.7

add_compile_definitions(QT_DISABLE_DEPRECATED_UP_TO=0x060600)

在QGC4.3.0源码中,提及QT_DISABLE_DEPRECATED_UP_TO只有这一处,但是,mingw编译器如何根据此值去确定是否编译呢? 

根据构建选项添加宏定义或者使能测试

if(CMAKE_BUILD_TYPE STREQUAL "Release")
    add_compile_definitions(
        NDEBUG
        QT_NO_DEBUG
        QT_NO_DEBUG_OUTPUT
    )
elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
    include(CTest)
    enable_testing()

    set(QT_ENABLE_VERBOSE_DEPLOYMENT ON CACHE BOOL "Verbose Deployment")
endif()

 如果是Release构建方式,添加编译器定义:NDEBUG、QT_NO_DEBUG、QT_NO_DEBUG_OUTPUT;如果是Debug构建,包含CTest模块,使能ctest测试,并设置QT_ENABLE_VERBOSE_DEPLOYMENT为ON。

vs code搜索QT_ENABLE_VERBOSE_DEPLOYMENT,无其它结果。

在Debug构建方式完成build之后,在test目录打开终端,输入:

ctest .

得到ctest结果如下:

Android环境下的配置

cmake_print_variables(QT_ANDROID_APPLICATION_ARGUMENTS QT_HOST_PATH)

 QT_ANDROID_APPLICATION_ARGUMENTS是指传递给android应用程序的参数列表,根据Qt官方文档(QT_HOST_PATH | Qt Core 6.7.1)。

交叉编译时,必须将此变量设置为主机平台的Qt安装位置。它用于查找要在主机上运行的工具(moc、rcc、androiddeployqt 等)。

list(APPEND QT_ANDROID_MULTI_ABI_FORWARD_VARS QGC_STABLE_BUILD)
list(APPEND QT_ANDROID_MULTI_ABI_FORWARD_VARS QT_HOST_PATH)
cmake_print_variables(QT_ANDROID_MULTI_ABI_FORWARD_VARS)

 向QT_ANDROID_MULTI_ABI_FORWARD_VARS添加QGC_STABLE_BUILD和QT_HOST_PATH。

根据Qt官方文档对QT_ANDROID_MULTI_ABI_FORWARD_VARS的介绍

QT_ANDROID_MULTI_ABI_FORWARD_VARS | Qt Core 6.7.1

QT_ANDROID_MULTI_ABI_FORWARD_VARS允许指定需要从主 ABI 项目转发到特定于 ABI 的子项目的 CMake 变量列表。由于多 ABI 项目生成过程的特殊性,没有通用方法来转发在命令行中或以其他类似方式指定的 CMake 缓存变量。这里添加了QGC_STABLE_BUILD、QT_HOST_PATH变量。

cmake_dependent_option(QT_ANDROID_SIGN_APK "Enable Signing APK" ON "CMAKE_BUILD_TYPE STREQUAL Release" OFF)
    if(QT_ANDROID_SIGN_APK)
        message(STATUS "Signing APK")
        message(STATUS "QT_ANDROID_KEYSTORE_PATH $ENV{QT_ANDROID_KEYSTORE_PATH}")
        message(STATUS "QT_ANDROID_KEYSTORE_ALIAS $ENV{QT_ANDROID_KEYSTORE_ALIAS}")
        # QT_ANDROID_KEYSTORE_STORE_PASS, QT_ANDROID_KEYSTORE_KEY_PASS
endif()

根据CMake官方文档CMakeDependentOption — CMake 3.29.2 Documentation

上面的cmake_dependent_option命令含义为:如果构建类型是Release,提供一个option名为QT_ANDROID_SIGN_APK,作用是“Enable Signing APK”,其值为ON,当构建类型不是Release,此option值为OFF。

下面根据QT_ANDROID_SIGN_APK的值做出处理,假如为ON,则if条件满足。

if(NOT Qt6LinguistTools_DIR)
set(Qt6LinguistTools_DIR ${QT_HOST_PATH}/lib/cmake/Qt6LinguistTools)
endif()

 如果Qt6LinguistTools_DIR变量不存在,设置Qt6LinguistTools_DIR变量为:${QT_HOST_PATH}/lib/cmake/Qt6LinguistTools

find_package

find_package(Qt6
    REQUIRED
    COMPONENTS
        Bluetooth
        Charts
        Concurrent
        Core
        Core5Compat
        Location
        Multimedia
        Network
        Positioning
        Quick
        QuickControls2
        QuickWidgets
        OpenGL
        Sql
        Svg
        Test
        TextToSpeech
        Widgets
        Xml
    OPTIONAL_COMPONENTS
        LinguistTools
        SerialPort
    HINTS
        ${QT_LIBRARY_HINTS}
)

cmake官方文档对find_package有详细介绍

find_package — CMake 3.29.2 Documentation

find_package有多种模式:

module mode,在此模式下,CMake 搜索名为 <PackageName>Find.cmake 的文件,首先在CMAKE_MODULE_PATH中列出的位置中查找,然后在 CMake 安装提供的查找模块中查找。如果找到该文件,则由 CMake 读取和处理该文件。

config mode,在此模式下,CMake 搜索名为 <lowercasePackageName>-config.cmake 或 <PackageName>Config.cmake 的文件。<lowercasePackageName>如果指定了版本详细信息,它还将查找 -config-version.cmake 或 <PackageName>ConfigVersion.cmake(有关如何使用这些单独版本文件的说明,请参阅配置模式版本选择)。

FetchContent redirection mode,类似于FetchContent_Declare() 和 FetchContent_MakeAvailable()

此外,Qt官方文档对此有说明:

Getting started with CMake | Build with CMake 6.7.1 (qt.io)

前文list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)

已经设置CMAKE_MODULE_PATH,如果是module mode,应该在Qt6安装目录下,或者QGC4.3.0源码的cmake目录下找到core.cmake, Bluetooth.cmake等cmake文件,找到了core.cmake类似文件:

 打开using-qt-core.cmake,内容如下:

find_package(Qt6 REQUIRED COMPONENTS Core)
target_link_libraries(mytarget PRIVATE Qt6::Core)

清楚指定link Qt6::Core,但是又回到起点,这里仍调用find_package(Qt6 REQUIRED COMPONENTS Core),需要解释此命令的执行。

如果是config mode,需要指定config mode search path,根据官方文档,有对config mode search procedure说明:

All calls to find_package() (even in Module mode) first look for a config package file in the CMAKE_FIND_PACKAGE_REDIRECTS_DIR directory. The FetchContent module, or even the project itself, may write files to that location to redirect find_package() calls to content already provided by the project. If no config package file is found in that location, the search proceeds with the logic described below.

在Qt Creator内部搜索CMAKE_FIND_PACKAGE_REDIRECTS_DIR,得到

打开其中一个CMakeCache.txt,有这样一行:

CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=E:/code/qgc/master/qgroundcontrol/build/Desktop_Qt_6_7_0_MinGW_64_bit-Debug/CMakeFiles/pkgRedirects

打开xxx/pkgRedirects,发现为空。

事情有点棘手,阅读Qt文档关于find_package有一句话:

For find_package to be successful, CMake must find the Qt installation. There are different ways you can tell CMake about Qt, but the most common and recommended approach is to set the CMake cache variable CMAKE_PREFIX_PATH to include the Qt 6 installation prefix. Note that Qt Creator will handle this transparently for you.

在Qt Creator搜索CMAKE_PREFIX_PATH,在其中CMakeCache.txt有一行:

CMAKE_PREFIX_PATH:PATH=F:/QT/6.7.0/mingw_64

指出的确为Qt安装路径,这时回到cmake官方文档关于config mode search procedure说明,假定CMAKE_PREFIX_PATH为下图的prefix,下图是cmake在config mode下搜索的路径选择:

CMAKE_PREFIX_PATH替换prefix,那么第6项有可能是:

F:/QT/6.7.0/mingw_64/lib/cmake/Qt6Core

也就是将name替换为Qt6Core,而在此目录下有Config.cmake文件

关于Qt的 find_package 目前还没搞懂~^ ^~,请指教。

  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值