全面剖析Qt6新版构建系统CMake

Qt自带集成开发环境(IDE),名为Qt Creator。它能够在Linux、OS X和Windows上运行,并提供智能代码完成、语法高亮、集成帮助系统、调试器和剖析器集成,还集成了全部主要的版本控制系统(如git、Bazaar)。除了Qt Creator外,Windows上的开发人员还可使用Qt的Visual Studio插件。也可使用其余的IDE(如KDE上的KDevelop)。但固然毫不是必须使用任何IDE。git

点击下载Qt6最新试用版编程

一年半前,Qt作出了一个重大决定,开始使用CMake来构建Qt 6。作出此决定的主要缘由是用户反馈。大多数Qt用户但愿更轻松地将他们的Qt项目与其余软件集成在一块儿。根据当时的研究,CMake显然是Qt用户中最经常使用的构建工具-除了qmake。此外,迁移到CMake还为咱们提供了摆脱内部构建工具维护负担的机会。架构

比决定更大的是迁移到CMake所需的工做。如今,基本的迁移工做已经完成,如今该分享咱们的发现了。编程语言

尽管已被许多项目很好地创建和使用,但CMake缺乏了先前Qt构建工具所支持的一些关键功能。这就是为何咱们与Kitware合做消除障碍并改善CMake的缘由,从而使Qt项目和更大的CMake社区受益。函数

因为各类因素,构建Qt很复杂:工具

  • Qt支持许多平台。
  • Qt分为可独立构建或所有构建的模块。
  • Qt支持不一样的构建方式(前缀,非前缀,不一样的功能集)

让咱们看一下Qt的构建工具开关引发或影响的CMake改进。大数据

Qt相关组件:优化

  • QtitanRibbon下载试用: 遵循Microsoft Ribbon UI Paradigm for Qt技术的Ribbon UI组件,致力于为Windows、Linux和Mac OS X提供功能完整的Ribbon组件。
  • QtitanChart | 下载试用 :是一个C ++库,表明一组控件,这些控件使您能够快速地为应用程序提供漂亮而丰富的图表。而且支持全部主要的桌面操做系统。
  • QtitanDataGrid | 下载试用 :这个Qt数据网格组件使用纯C++建立,运行速度极快,处理大数据和超大数据集的效果突出。QtitanDataGrid彻底集成了QtDesigner,于是极易适应其余类似的开发环境,保证100%兼容Qt GUI。

预编译头ui

在C ++项目中,可能会一遍又一遍地包含相同的头文件。对于库头尤为如此。若是工具链支持,则能够经过预编译头文件来加快编译速度。url

在最长的时间内,CMake并未为此提供现成的支持。可是,在网上搜索代码片断以启用CMake中的预编译头的日子已通过去。从CMake 3.16开始,使用该target_precompile_headers命令能够添加要预编译的头文件列表。

Unity构建

另外一种加快编译速度的方法是unity builds。这就是多名技术--它也被称为巨型构建、合并构建和单一编译单元。

这种技术建立了一个包含全部其余源文件的源文件,而且只编译这一个源文件。

#include "source_file1.cpp"
#include "source_file2.cpp"
/*...*/
#include "source_file8.cpp"

全部源文件的包含文件仅被处理一次,全部内容都以一个翻译单元结束,而且优化器对项目具备全局视图。

可是,并不是每一个C ++项目均可以不加修改地利用统一构建。

depfile支持AUTOMOC + Ninja

长期以来,人们一直在抱怨CMake的AUTOMOC,它会没必要要地运行,或者在再次调用moc时没法正确检测到。缘由之一是moc输出的确切依赖关系对于AUTOMOC是不可见的。

从Qt 5.15开始,moc学会了写出准确的文件,这些文件构成了moc输出的依赖性。CMake 3.17学会了读取moc的depfiles并将其用于Ninja生成器。

总结一下:使用Ninja生成器的Qt> = 5.15和CMake> = 3.17时,AUTOMOC知道正确的依赖项,能够在正确的时间从新运行moc。

Ninja Multi-Config

在Windows和macOS上,传统上Qt是用两种配置(调试和发布)构建的,但在一个构建目录中。

直到版本3.17引入了一个名为“ Ninja Multi-Config”的新生成器后,CMake才提供实现此目的的方法,该生成器能够一次构建多个配置。

iOS多架构构建

适用于iOS的Qt提供了模拟器和设备版本,该版本将针对实际目标构建的Qt与针对iOS模拟器构建的Qt相结合。尽管CMake 3.17引入了Ninja Multi-Config,但它的iOS支持还没有为iOS多体系结构构建作好准备。

CMake 3.18解决了这个问题,咱们能够很高兴地为模拟器和设备进行构建。

文件(配置)

在Qt构建中,在配置时会生成大量带有动态建立内容的文件。configure_file可是,该命令仅使用输入文件,不使用字符串。

解决此问题的一种方法是让输入文件只有一个变量

--conf-file-content.txt.in--
@my-conf-file-content@

而后像这样调用configure_file

set(my-conf-file-content "This is the generated content!")
configure_file("my-conf-file-content.txt.in" "output.txt" @ONLY)

在CMake 3.18中,咱们能够轻松实现相同目标:

file(CONFIGURE OUTPUT "output.txt" CONTENT "This is the generated content!")

评估!与功能同盟!

在Qt构建中,咱们用尽了CMake语言做为实际编程语言执行的能力。不只应该由用户调用CMake函数,并且在引擎盖下还有更复杂的设备。

让咱们烦恼的一件事是,不可能动态调用函数。在qmake中,能够调用在变量中定义的函数,而且Qt5版本普遍使用此功能。

f = message
$${f}("Hello World!")

有多种方法可使此工做在CMake中进行,包括生成一个随后包含的文件,可是特别是在Windows上,这将极大地减慢项目配置步骤。

CMake 3.18随附cmake_language(EVAL)用于评估CMake代码并cmake_language(CALL)调用宏或函数。

set(f "message")
cmake_language(CALL ${f} STATUS "Hello World!")
cmake_language(EVAL CODE "${f}(\"Hello World!\")")

稍后致电-延迟的代码

一样,qmake功能启发了CMake命令。

在QMake项目中,能够编写CONFIG += foo,而后在mkspecs/features/foo.prf处理实际的项目文件后加载。

这对于面向用户的API尤为有用。假设您正在为Android建立一个项目。

qt_add_executable(MyApp)
set_property(MyApp TARGET PROPERTY QT_ANDROID_EXTRA_LIBS SuperDuperLib)
qt_finalize_executable(MyApp)

该qt_finalize_executable调用将根据目标的属性为目标生成适当的部署设置。若是用户忘记致电qt_finalize_executable,则不会生成部署设置,也不会出现错误或警告。

可是,若是用户摆脱了打电话的负担,那会不会很棒qt_finalize_executable?在CMake 3.19中,Qt构建利用了新命令cmake_language(DEFER CALL)。这样一来,就能够在定义的时间调用函数,例如,在评估当前目录的项目文件以后。

不一样目录范围的源文件上的属性

在某些地方,咱们为模块建立目标,而后在子目录中将源文件添加到该目标。这样可使源文件的名称与CMakeLists.txt文件保持接近。

可是,没法在这些位置指定每一个源文件的属性-咱们必须进入层次结构的顶层才能进行设置。咱们并不常常这样作,可是有时在开发过程当中会出现这种状况,以容许根据选项设置在编译时选择实验功能。

在CMake 3.18中,set_source_files_properties学会了在不一样目录范围内设置属性:

该DIRECTORY选项获取指向处理后的源目录的路径的列表,并TARGET_DIRECTORY获取目标的列表,这些目标的源目录将用做设置源文件属性的做用域列表。

get_property()而且get_source_file_property()还具备相同的新参数,除了只能指定一个值而不是列表。

add_custom_command DEPFILE支持Makefile

CMake 3.20将为Unix Makefile生成器提供depfile支持。这也是将moc生成的depfile用于Makefile的前提。