CMake使用教程和原理

  • 2019 年 12 月 28 日
  • 筆記

一、什么是CMake

CMake是一个主要用于CPP的构建工具。CMake语言是平台无关的中间编译工具。同一个CMake编译规则在不同系统平台构建出不同的可执行构建文件。在Linux产生MakeFile,在Windows平台产生Visual Studio工程等。CMake旨在解决各平台的不同Make工具的产生的差异(比如GNU Make, QT的qmake,微软的nmake, BSD的pmake)。

其实除了CMake构建系统之外,CMake已经发展出一系列开发工具:CMake,CTest,CPack和CDash。

– CMake是负责构建软件的构建工具。

– CTest是一个测试驱动程序工具,用于运行回归测试。

– CPack是一种打包工具,用于为使用CMake构建的软件创建特定于平台的安装程序。

– CDash是一个Web应用程序,用于显示测试结果并执行连续的集成测试。

– 其他还有Doxygen和BullseyeCoverage

1.1 CMake的前世今生

项目的通常做法是为Unix平台提供配置脚本和Makefile,为Windows提供Visual Studio项目文件。autoconf / libtool构建软件的方法不能满足跨平台的要求。

历史上曾经出现的1999年的VTK构建系统。该系统由Unix的配置脚本和pcmaker Windows 的可执行文件组成。pcmaker是一个C程序,可以读取Unix Makefile文件并为Windows创建NMake文件。

另一种是是gmake针对Sun工作站上C ++计算机视觉环境。Sun工作站使用该imake系统创建Makefile。但是,有时需要Windows端口时,gmake才创建了系统。Unix编译器和Windows编译器均可与此gmake基于此的系统一起使用。

这两个系统都存在严重缺陷:它们迫使Windows开发人员使用命令行。有经验的Windows开发人员更喜欢使用集成开发环境(IDE)。

1.2 Cmake的使命

  • 创建和源代码库隔离的构建目录,分离开发和构建目录。易于进行源代码版本控制。
  • CMake是具有管理依赖项,依赖之间的关系。如果变更了源文件,必须重新构建所有依赖该源文件的脚本。
  • 并且要求高效的依赖关系解析是耗时短的。
  • CMake提供一些易于操作的API,向开发人员屏蔽平台细节。

二、CMake怎么解决问题

CMake有两个阶段,配置和生成阶段。

图1、CMake配置和生成阶段

2.1 配置阶段

配置阶段解析所有的输入变量,并存储在CMakeCache.txt这个文件。这个阶段解决了用户构建一个项目需要依赖的各种输入参数。

在项目的构建过程中都使用shell级别的环境变量。通常,项目具有指向根目录位置的PROJECT_ROOT环境变量。还有配置可选或外部程序包。要使构建正常进行,每次执行构建时都需要设置所有这些外部变量。所有CMakeFile在配置阶段解决了这个问题。

先来窥探下CMakeCache.txt的构成,CmakeCache.txt由两部分构成:External Cache Entries和Internal Cache Entries。而CMakeCache.txt是由解析器Parser生成。解析器的匹配器找到各种token。CMakeLists也可以解析外部的CMake语法,他是由“include” 或者“add_subdirectory”包含进来,两者的区别后面会说到。

解析完这些变量,cmake在内存中有了项目(可执行程序、库、用户自定义Command)的构建表达方法。在代码中一个target用cmTarget对象表示,所有的cmTarget构成了cmMakefile对象。

图2、CMakeCache.txt的 外部输入变量
图3、CMakeCache.txt的内部输入变量

2.2 生成阶段

在生成阶段,cmake使用了一套语法解析系统,关键的类图如下。cmMakefile对象存错了CMakeLists.txt的所有输入变量。解析器使用了lex/yacc语法解析器,执行构建动作。cmCommand定义了命令的执行动作,并且该动作的注释在代码也有注释。

图4、生成阶段的关键类

2.3 依赖管理