CMake实战指南 - 2 建立工程

如果没有构建系统,那么一个工程就仅仅是一系列文件的集合,而CMake的出现为此定义了一些秩序。CMake的构建过程始于一个叫CMakeLists.txt的文件,这个文件里定义了编译什么、如何编译、运行什么测试用例以及如何打包程序,同时,CMakeLists.txt文件也是一个平台无关的项目文件,CMake之后会将该文件转换成具体平台构建工具相关的项目文件。而从CMakeLists.txt文件的后缀名可以看出,它仅仅是一个普通的文本文件,开发者可以使用自己喜欢的文本编辑器或者其他开发工具编辑其内容。关于CMakeLists.txt文件中的内容将在后续章节中介绍,现在大家仅需知道CMakeLists.txt文件中包含了CMake在整个构建过程中所需做的所有事情。
对于CMake而言,一个项目至少应有源目录和二进制目录。其中源目录指的是CMakeLists.txt所在的目录,项目中的源码文件以及其他文件通常也存放在这一目录中,同时该目录也通常由版本管理工具如git、svn或者其他工具管控。
二进制目录,它常用来存放构建过程中产生的所有文件,在开发者的圈子里,二进制目录还有一个更容易被人接受的名字叫做构建目录。在本书中,我们更倾向与使用后者。CMake、CTest、CPack以及平台相关的构建工具相关的各种文件,如可执行文件、链接库文件、测试输出文件以及打包后的文件等等,同时CMake也会在构建目录中生成一个名叫CMakeCache.txt的特殊文件,这个文件主要记录一些内容信息以便在后续构建过程中重复利用,后续章节我们将会详细讨论相关场景。平台的开发工具如Xcode和Visual Studio等也会在构建目录生成一些相关文件。通常构建目录中的文件都不在版本控制工具的受控范围内。CMakeLists.txt文件是关于项目的一般性描述,而生成的项目文件却是构建输出的产物,这也是CMakeLists.txt文件与其他文件的一个区别。
当开发者着手与项目开发时,首先应该明确构建目录相较于源目录的位置,为此产生了两种方式,这里我们称呼为源内构建(in-source)和源外构建(out-of-source)。

2.1 源内构建

源内构建,也就是说构建目录和源目录是同一个,但通常不推荐这种编译方式。而新手在刚刚接触CMake时往往都是采用这种方式,因为相较于源外编译,源内构建要简单了很多。但由于源内构建方式中的构建目录和源目录是同一个,所以后续构建生成的所有文件都会和项目中的源文件混淆在一起,对于项目管理就会变得非常的麻烦,而且也会存在项目源码文件被覆盖的风险。同时,由于源目录中存在了许多构建过程中产生的临时文件,这对于版本管控往往也是一个非常大的挑战,为了版本管理工具可能需要定义一系列规则来忽略这些文件。由于临时文件的存在,项目的源码树往往也无法保持一种“干净”的状态。基于上述的种种原因,不建议开发者使用源内构建这种构建方式,即使是很简单的项目。

2.2 源外构建

相较于源内构建,源外构建是一种更被接受的构建方式。由于它的构建目录和源目录不是同一个目录,所以就被称为源外构建。采取这种方式,构建过程中产生的文件和项目的源码文件就会完全的独立开,从而不会产生混淆的问题。另外采用源外编译,开发者可以针对同一个源目录创建不同的构建目录,每个构建目录都可以采用不同的构建选项,比如:
在这里插入图片描述
源外构建的一种通用方式就是将构建目录作为源目录的子目录,这样既可以充分利用源外构建的优势,同时又可以使构建目录不完全独立与源目录,而一些持续构建系统出于对外部目录访问权限的考虑或多或少都会考虑采用这种方式。通常对于构建目录,我们在起名字时都会考虑以build开头,这样也会大大方便我们的版本管理工具。

2.3 生成项目文件

当项目目录结构确定之后,开发者通常就会执行CMake,它会先读取CMakeLists.txt文件,然后在build目录中生成项目文件,而项目文件的生成通用依赖与开发者所选择的生成器。CMake支持如下列表中的生成器:

类别生成器示例是否支持多配置
Visual StudioVisual Studio 17 2022 / Visual Studio 16 2019Yes
XcodeXcodeYes
NinjaNinja / Ninja Multi-ConfigNinja Multi-Config(No), Ninja Multi-Config(Yes)
MakefilesUnix Makefiles / NMake MakefilesNo

一些生成器在生成项目文件时支持多配置,如Debug、Release等,开发者无需重新运行CMake就可以选择不同的配置,这对于那些IDE开发环境来说非常的便利。对于那些不支持多配置的生成器来说,开发者在重新运行CMake时必须显示的切换不同配置。这些操作在IDE中操作非常便利,并且也不会捆绑到具体的编译器。
运行CMake最基本的方式就是通过cmake命令行工具,这是最简单的方式,通过命令行可以修改构建目录,同时也可以传递一些可选项用于生成器以及源码树等等,比如:

mkdir build
cd build
cmake -G "Unix Makefiles" ../source

-G是生成器选项,如果在执行cmake时没有-G选项,那么CMake就会根据当前运行平台选择一个默认的生成器。在CMake 3.15及之后,可以通过CMAKE_GENERATOR环境变量修改默认的生成器。对于所有的生成器,CMake会做一系列的测试来确定如何生成项目文件,如检查编译是否正常,检查编译器特征及其一些其他测试。一旦CMake完成这些测试,就会有如下日志输出:

-- Configuring done
-- Generating done
-- Build files have been written to: /some/path/build

从上述信息可以看出,项目文件的生成实际主要包含两步:配置以及生成。在配置阶段,CMake会读取CMakeLists.txt文件内容,然后生成一个完整工程的内部描述。在配置完成之后,生成阶段会创建所有的项目文件。对于学习CMake基础的阶段,配置和生成之间其实并没有多大的区别,但在随后的章节中,这两个阶段的区别会变的非常重要,详细可以参考11章节。
当CMake运行完成后,它会在build目录中保存一个名叫CMakeCache.txt的文件,当cmake重新运行时,它会复用该文件中的一些信息从而加速项目的生成。后续章节中也会提到,该文件还运行开发者选择性存储信息。cmake-gui是cmake的图形化程序,在后续的第6章节中会详细介绍。

2.4 运行构建工具

当运行完cmake之后,所有的项目文件已经准备就绪,开发人员可以按照他们习惯的方式使用他们选择的构建工具。在构建目录中包含了所需的项目文件,这些文件可以被加载到IDE中并且被命令行工具读取,另外,cmake可以通过如下命令直接调用调用工具:

cmake --build /pathTo/build --config Debug --target MyAp

这或许更适用于那些习惯使用IDE进行开发项目的开发者们。–build选项主要用于指定构建目录。对于多配置的生成器,–config选项用于指定构建的配置选项,而对于单配置的生成器其会自动忽略该选项,并且仅依赖执行cmake项目步骤时提供的信息,在第15章节中会深入介绍构建配置的相关内容。–target选项用于告诉构建工具构建哪个目标,如果没有指定,则会构建默认目标。对于CMake 3.15或者之后的版本可以在–taget添加多个目标。
虽然开发人员通常会在日常开发中直接调用他们选择的构建工具,如上所示,通过cmake命令调用它在驱动自动化构建。使用这种方法,一个简单的脚本构建可能看起来像这样:

mkdir build
cd build
cmake -G "Unix Makefiles" ../source
cmake --build . --config Release --target MyApp

如果开发人员希望尝试不同的生成器,那么cmake -G 选项是唯一需要改变的,因为构建工具将自动调用,构建工具甚至不必在PATH变量中,开发者需要做的可能仅是在cmake初次调用时指定。

2.5 练习

尽管是初次使用CMake,但还是非常建议让构建目录和源码树独立开。要想体验这种方法的好处,可以尝试针对同一份源目录创建不同构建目录,比如一个目录用于Debug模式构建,另一个用于Release构建。另外也可以尝试不同的构建目录对应不同的生成器,比如Unix Makefiles和Xcode。这非常有助于捕捉对特定构建的任何意外依赖工具,或检查生成器类型之间的不同编译器设置。
在项目的初期,特别是那种不考虑跨平台的项目,建议仅针对单一的生成器构建项目。随着项目的推进,项目也许就会需要支持不同的平台及生成器。定期使用与开发人员通常使用的项目生成器不同的项目生成器检查构建,也许会省去由于无关的生成器相关的代码导致的痛苦,同时,这也为未来项目使用不同的生成器提前铺路。为此建议每个项目除了平台默认的构建器外,再额外增加一个构建起用于构建项目。通常,Ninja生成器是一个非常不错的选择,它拥有所有生成器中最广泛的平台支持,而且它还创建了非常高效的构建。如果项目构建考虑脚本化,那么建议通过cmake --build命令精选构建,而不是直接使用构建工具使用构建项目,这样就可以在脚本中直接在不同构建器间切换而不用修改任何东西。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值