前言
CMake是一个跨平台的、开源的构建工具,主要用于管理和生成项目的构建文件。CMake允许开发者以一种平台无关的方式定义项目的构建过程,然后生成特定于平台的构建文件。而Qt-CMake不是一个单独的工具,而是指在使用CMake构建Qt项目时所需要的配置和支持,涉及将Qt特性集成到CMake构建系统中。
一般在Linux平台,Qt-CMake会生成Makefile文件,而在Windows平台,默认是生成build.ninja文件。
正文
这里我们先来简单介绍一下编译代码的过程,再来详细说明CMakeLists.txt文件的内容。
一般情况下,为了不让编译产生的中间文件污染我们的工程,我们可以创建一个cmake-build-debug
目录,然后进入该目录,执行cmake ..
,这时的CMake工具会去上一级目录中查找CMakeLists.txt文件,当然最好不要在源码目录这样干,在源码上一层目录新建构建目录最好。
然后会生成Makefile文件,执行cmake --build .
进行编译代码,便可以生成可执行文件。
下面便是常见的Qt项目的CMakeLists.txt的分析:
-
cmake_minimum_required(VERSION 3.21.1)
:设置cmake
需要的最低版本。 -
option(<option_variable> "<option_description>" <initial_value>)
:用于定义一个用户可配置的选项,其中<option_variable>
定义一个CMake
变量,用于存储该选项的状态,<option_description>
是选项的描述信息,<initial_value>
是选项的初始值,一般为ON
或者OFF
。说白了就是定义一个变量,在
CMakeLists.txt
中使用。比如QML默认的2个配置:option(LINK_INSIGHT "Link Qt Insight Tracker library" ON) option(BUILD_QDS_COMPONENTS "Build design studio components" ON)
第一个是是否需要链接Qt Insight Tracker库,该库是一个应用程序和嵌入式设备的智能分析工具,然后该变量的后面的使用是:
if (LINK_INSIGHT) include(${CMAKE_CURRENT_SOURCE_DIR}/insight) endif ()
第二个是是否构建Qt Design Studio的组件,该工具可以为设计师和开发人员快速构建
UI
的工具,后面的使用是:if (BUILD_QDS_COMPONENTS) include(${CMAKE_CURRENT_SOURCE_DIR}/qmlcomponents) endif()
合理使用
option
进行合理化的构建,可以节省构建资源,加快速度。 -
project(HelloQMLApp LANGUAGES CXX)
:设置项目名称、编程语言等,如果不设置编程语言,CMake
会根据项目中的文件类型自动推断出所使用的编程语言。 -
set(CMAKE_AUTOMOC ON)
:告诉CMake
在构建过程中自动运行moc(Meta-Object Compiler)
工具来处理包含了Q_OBJECT
宏的C++
源文件。当C++类中包含有Q_OBJECT
宏时,这意味着该类涉及了信号槽机制,需要通过moc
工具生成额外代码。这里的
set
的作用就是定义或者修改CMake变量的值,CMake变量用于存储和传递构建配置的各种信息,比如文件路径、编译选项、库版本等。 -
find_package()
是CMake中用于查找并且加载外部软件包的一个命令,通常用于引入和管理项目所需的第三方库或者模块。基本语法是:
find_package(<package_name> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [COMPONENTS [components...]] [OPTIONAL_COMPONENTS components...] [NO_POLICY_SCOPE])
其中参数说明:
<package_name>
:要查找的软件包的名称;[version]
:可选项,指定软件包的版本号;[EXACT]
:可选项,要求精确匹配指定版本的软件包;[QUIT]
:可选项,安静模式,不输出查找过程的详细信息;[REQUIRED]
:可选项,要求必须找到指定的软件包,否则会引发错误;[COMPONENTS] [components ...]
:指定要查找的软件包的组件。
在QML项目中,默认有
find_package(Qt6 6.2 REQUIRED COMPONENTS Core Gui Qml Quick)
表示需要加载Qt6.2
,并且要求Core
、Gui
等几个组件。这里值得关注的点是如果使用交叉编译的
qt-cmake
工具来构建项目,这里就会寻找到交叉编译的库。 -
qt_add_executable(HelloQMLApp src/main.cpp)
:该指令和add_executable
不同,它是Qt6
中用于添加一个可执行文件的函数调用。该语句的作用是将名为HelloQMLApp
的可执行文件与指定的源文件src/main.cpp
相关联。功能包括如下几点:- 创建可执行文件,在项目中创建一个名为
HelloQMLApp
的可执行文件。 - 指定源文件,源文件
src/main.cpp
就是入口源文件。 - 与Qt相关联,由于是使用
Qt6
构建项目,qt_add_executable()
函数会自动处理与Qt相关的配置,例如生成moc
文件,以确保Qt功能正常使用。 - 简化配置,有助于简化项目的配置过程,特别是涉及到Qt功能的部分。
- 创建可执行文件,在项目中创建一个名为
-
qt_add_resources
的作用是将二进制资源编译为源代码,这个比较有意思,该指令的使用是:qt_add_resources(<TARGET> <RESOURCE_NAME> [PREFIX <PATH>] [LANG <LANGUAGE>] [BASE <PATH>] [BIG_RESOURCES] [OUTPUT_TARGETS <VARIABLE_NAME>] [FILES ...] [OPTIONS ...])
其中
<TARGET>
是目标,即往哪个程序或者库中添加资源;<Resource_Name>
是资源名,自定义;PREFIX PATH
是可选的,指定路径资源,即访问该资源需要的前缀,默认是/
;FILES
是可选的,指需要添加的二进制资源文件。比如代码:
qt_add_resources(${PROJECT_NAME} "txt" PREFIX "txt" FILES in.txt )
如果要访问
in.txt
,则需要file.setFileName(":txt/in.txt");
。同理,在默认项目中有如下代码:
qt_add_resources(HelloQMLApp "configuration" PREFIX "/" FILES qtquickcontrols2.conf )
即把
qtquickcontrols2.conf
当作资源文件,添加进项目中。
-
target_link_libraries
与target_include_directories
的作用是用于配置目标文件(可执行文件或者库)的编译与链接选项。比如在项目中有代码:target_link_libraries(HelloQMLApp PRIVATE Qt6::Core Qt6::Gui Qt6::Qml Qt6::Quick )
将
Qt6
模块链接到名为HelloQMLApp
上,以便在构建目标文件时可以使用这些模块提供的功能和库。同时,使用私有链接,意味着只有HelloQMLApp
可以访问这些链接的内容,其他目标无法直接访问。 这里的参数可以是静态库、动态库或者其他目标的库,这个指令告诉链接器在生成目标文件时需要链接哪些库。再比如下面代码:
target_include_directories(${target_name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
就是去规定的目录中查找头文件,头文件包含了原文件编译所需的接口定义与声明。
-
target_compile_definitions
命令用于为指定的目标添加预处理的宏定义,类似在编译命令行中使用-D
选项。比如下面代码:target_compile_definitions(${target_name} PRIVATE CONFIG_LIBRARY)
就是定义了一个宏,可以在C++代码中判断该宏有没有定义。
-
include
命令用于包含外部文件或者脚本文件到当前CMakeLists.txt
文件中,包括其他的CMakeLists.txt
、模块文件、函数文件、宏文件等,以便在当前的构建过程中使用他们。include(GNUInstallDirs)
用于包含GNU安装目录相关的定义和变量,主要是获取一些GNU安装目录相关的变量在后面可以使用,比如${CMAKE_INSTALL_LIBDIR}
。 -
install
命令用于配置安装规则,指定在构建完成后,如何将生成的文件安装到指定的位置。安装规则通常用于将构建生成的文件(如可执行文件、库文件、头文件等)安装到系统的特定目录,以便用户可以访问这些文件。比如在项目中:
install(TARGETS HelloQMLApp BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
作用就是用于安装
HelloQMLApp
的目标文件到不同的目录中,具体来说就是将目标文件安装为一个包(bundle
)时,将其安装到当前构建目录下。当将HelloQMLApp
安装为一个库文件时,将其安装到${CMAKE_INSTALL_LIBDIR}
目录中。当将HelloQMLApp
安装为一个运行时文件时,安装到${CMAKE_INSTALL_BINDIR}
目录中。
-
set
命令用于设置变量的值,可以用于创建新变量、更新已存在的变量或者删除变量。基本语法是:set(<variable> <value> [CACHE <type> <docstring> [FORCE]])
各个选项的作用:
variable
表示要设置的变量名,可以是已存在的变量,也可以是一个新的变量。value
是要设置的变量,可以是简单的字符串或列表,也可以是一个表达式或者函数调用。CACHE <type> <docstring>
将变量设置为一个缓存变量,以便用户可以通过命令行或者配置工具将其修改。type
是变量类型,docstring
为对变量的描述。
比如在项目中有:
set(QML_IMPORT_PATH ${PROJECT_BINARY_DIR}/qml CACHE PATH "Path to the custom QML components defined by the project")
作用就是定义QML组件的导入路径,其中
PATH
表示这个缓存变量是路径。总结
关于CMake还有更多的知识需要学习,这里简单地介绍一下Qt项目的CMakeLists.txt,后续持续更新。