为了将源码转化为最终用户可以实际使用的东西,需要使用到编译器、链接器、测试框架、打包系统等,这些都增加了开发高质量、健壮性软件的复杂性,虽然一些IDE
能够将这些过程简化一点,但是开发跨平台的软件并不是总能用到这些IDE
的特性。
幸运的是, CMake
就是一套可以使上述开发过程易于管理的一套工具,它涵盖了从建立代码工程到发布包的所有过程everything),CMake
不仅涵盖了所有的开发流程,还支持广泛的平台、工具和不同的编程语言。
CMake
使用的几个阶段如下:
CMake
最出名的阶段-使用项目描述文件,生成特定平台的项目文件,这些生成的项目文件适合开发者结合(make
、Xcode
、Visual Studio
)使用。上述整个过程CMake
都可以通过调用对应的工具完成,甚至构建工具(make)也可以被CMake
调用。
脱离构建系统,工程只是一个文件的集合。
CMakeLists.txt
是一个平台无关的描述文件。CMake
使用可读文件CMakeLists.txt
为工程的构建,制定了一些规则,定义了什么文件应该编译以及如何编译、跑那些测试和创建什么包,使用该描述文件生成特定平台相关工程文件。
CMake
的基本观念就是项目同时要拥有一个源码路径和二进制文件目录,源码目录是放置CMakeLists.txt
文件、源码文件和一些需要构建的文件的地方,源码目录通处于git、subversion
或者类似工具的版本控制之下。
所有构建过程生成的文件都会放置到二进制目录,因此二进制目录通常也被称为构建目录。本书中倾向于使用构建目录,因为这样更直观。CMake
调用构建工具(eg: make
)、CTest
和CPack
的过程中会在构建目录中生成一系列的文件,可执行文件、库、测试输出和包都在构建目录中。CMake
还会在构建目录中生成一个名为CMakeCache.txt
的特殊文件,用于存储各种后期运行时可重用的信息,开发人员不需要关心CMakeCache.txt
文件,后面章节会讨论CMakeCache.txt
文件。构建工具的项目文件也是在构建目录中创建的(eg:makefile
),这些CMake
生成的文件不应该处于版本控制之下。
虽然不是很鼓励这样做,但是在使用CMake
时是可以在源码的目录进行构建的,并将这种构建方式称为内源构建in-source build
,因为这种方式更加简单,所以开发者刚开始通常会使用这种构建方式。
在源码目录进行构建的主要问题:
基于以上原因,不建议开发人员在源码中进行构建,即使是一个简单的项目
out-of-source builds
)在源码外构建更加可取,因为:
本书将始终使用源码外构建,并和遵循源目录和构建目录位于公共父目录下的模式,构建根目录将称为build
一些开发人员会使用该方法的一些变体,将构建目录作为源目录的子目录,这样做虽然能顾有在源码外构建的大部分优势,但是让然会有部分内源构建的部分缺点,除非有很好的理由这样使用,否则建议将构建目录完全置于源码树之外。
目录结构定下来后,开发人员可以运行CMake
,它读入CMakeList.txt
文件并在构建目录中创建项目文件。开发人员通过选择特定的项目文件生成器,来选择要创建的项目文件的类型。支持一系列不同的生成器,下表列出了更常用的生成器。
Category |
Generator Examples |
Multi-config |
---|---|---|
Visual Studio |
Visual Studio 15 2017 |
YES |
Visual Studio |
Visual Studio 14 2015 |
YES |
Xcode |
Xcode |
YES |
NinJa |
NinJa |
NO |
Makefiles |
UNIX Makefiles |
NO |
Makefiles |
MSYS Makefiles |
NO |
Makefiles |
MinGW Makefiles |
NO |
Makefiles |
NMake Makefiles |
NO |
Multi-config
-是否支持多配置构建项目,支持就可以在不重新运行CMake
的前提下构建不同的项目(eg: debug release
)
最简单的调用CMake
方式
cmake
mkdir build
cd build
cmake -G "Unix Makefiles" ../source
如果省略-G
选项,cmake
会根据主机的平台选择默认的生成器类型。对于所有的生成器类型,CMake
将执行一系列的测试并询问系统,以确定如何建立项目文件。这些工作包含验证编译器是否工作、确定支持的编译器特性集和其他的各种任务,在CMake
完成之前将会给出类似如下的日志信息:
-- Configuring done
-- Generating done
-- Build files have been written to: /some/path/build
上面强调了项目文件的创建,实际上包含两个步骤-配置和生成。在配置阶段,CMake
通过读取CMakeLists.txt
文件完成对整个项目的内部表示的构建。在完成这些之后,生成阶段创建项目文件,配置和生成对与基本的CMake
使用,并不是很重要,但是在后面的章节中,配置和生成分离变得很重要。会在Chapter 10, Generator Expressions.
章节中进行更加详细的介绍。
当首次完成CMake
的运行时,它将在构建目录中保存一个cmakecase.txt
的文件,CMake
使用这个文件来保存详细信息,这样当它再次运行时,他可以重用第一次计算的信息,并加速项目的生成。后面的章节将会介绍如何使用该文件在不同的运行之间保留开发者选项。CMake
的gui
程序使用将在第5章中进行介绍。
此时,项目文件已经可用,开发人员可以按照他们习惯使用他们选择的构建工具。构建目录将包含必要的项目文件,这些文件可以加载到IDE
中、通过命令行工具读取等,或者CMake
能够代表开发者调用构建工具如:
cmake --build /some/path/build --config Debug --target MyApp
使用Xcode
或Visual Studio
这样IDE
的开发者,更加习惯这种工作方式。build
选项指向生成步骤中使用的构建目录对于支持多配置生成器,config
选项指定要构建哪个配置,而单个配置生成器将忽略--config
选项,详细信息将在第13章中进行介绍,target
选项可以用来告诉构建工具要构建什么,或者如果省略将构建默认的目标。
虽然在日常开发中,开发人员通常自己调用构建工具,但是通过cmake
进行调用在脚本驱动的自动化构建中更加的有用。使用这种方法,一个简单的脚本构建如下:
mkdir build
cd build
cmake -G "Unix Makefiles" ../source
cmake --build . --config Release --target MyApp
如果开发人员想更换不同的生成器,所需要做的就是更改-G
参数,然后将cmake
将自动调用正确的构建工具。
即使首次使用cmake
也建议将构建目录与源码进行完全分离,为相同的源码目录设置两个设置跟多不同的构建。
跨平台工作的开发者,定期使用不同生成器进行构建