前言:
学习笔记,随时更新。如有谬误,欢迎指正。
说明:
- 红色字体为较为重要部分。
- 绿色字体为个人理解部分。
18 用户界面指南
18.1 介绍
如果一个软件包提供了一个基于 CMake 的构建系统和他们的软件的源代码,软件的消费者需要运行一个 CMake 用户交互工具来构建它。
行为良好的基于 CMake 的构建系统不会在源码目录中创建任何输出,因此通常情况下,用户执行源外构建并在那里(源外构建的位置)执行(程序的)构建。首先,必须指示 CMake 生成合适的构建系统,然后用户调用构建工具来处理生成的构建系统。生成的构建系统是特定于用于生成它的机器的,并且不可重新分发。所提供的源码软件包的每个消费者都需要使用 CMake 生成特定于其系统的构建系统。
生成的构建系统通常应该被视为只读的。 CMake 文件作为主要的产物应该完全指定构建系统,并且没有理由(需要)在 IDE 中手动填充属性,例如在生成构建系统之后, CMake 将定期重写生成的构建系统,因此用户的修改将被覆盖。
通过提供 CMake 文件,本手册中描述的特性和用户界面可用于所有基于 CMake 的构建系统。
当处理提供的 CMake 文件时, CMake 工具可能会向用户报告错误,例如报告编译器不支持,或者编译器不支持所需的编译选项,或者无法找到依赖项。这些错误必须由用户通过选择不同的编译器、安装依赖项或指示 CMake 在哪里找到它们等方式来解决。
18.1.1 cmake 命令行工具
cmake 的一个简单但典型的用法是在一个新的软件源代码副本上创建一个构建目录并在那里调用 cmake :
$ cd some_software-1.4.2
$ mkdir build
$ cd build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/opt/the/prefix
$ cmake --build .
$ cmake --build . --target install
建议在与源代码不同的的单独目录中构建,因为这样可以保持源目录的原始状态,允许使用多个工具链构建单个源代码,并且可以通过简单地删除构建目录轻松地清除构建的产物。
CMake 工具可能会报告警告,这些警告是针对软件的提供者,而不是针对软件的消费者。这样的警告以“此警告是针对项目开发人员的”结尾。用户可以通过向 cmake 传递 -Wno-dev 标志来禁用此类警告。
18.1.2 cmake-gui 工具
更习惯于 GUI 界面的用户可以使用 cmake-gui 工具来调用 CMake 并生成一个构建系统。
首先必须填充源码目录和二进制目录。总是建议对源代码和构建使用不同的目录。

18.2 生成构建系统
有几个用户界面工具可以用来从 CMake 文件生成构建系统。 ccmake 和 cmake-gui 工具指导用户设置各种必要的选项。可以调用 cmake 工具来指定命令行上的选项。本手册描述了可以使用任何用户界面工具设置的选项,尽管每个工具设置选项的模式不同。
18.2.1 命令行环境
当使用命令行构建系统(如 Makefiles 或 Ninja )调用 cmake 时,有必要使用正确的构建环境来确保构建工具可用。 CMake 必须能够根据需要找到合适的构建工具、编译器、链接器和其他工具。
在 Linux 系统上,适当的工具通常在系统范围的位置提供,并且可以很容易地通过系统包管理器安装。也可以使用用户提供的或安装在非默认位置的其他工具链。
在交叉编译时,一些平台可能需要设置环境变量,或者可能提供脚本来设置环境。
Visual Studio 提供了多个命令提示符和 vcvarsall.bat 脚本,用于为命令行构建系统设置正确的环境。虽然在使用 Visual Studio 生成器时并不一定要使用相应的命令行环境,但这样做没有任何缺点。
当使用 Xcode 时,可以安装多个 Xcode 版本。选择哪一个可以有很多不同的方法,但最常见的方法是:
- 在 Xcode IDE 的首选项中设置默认版本。
- 通过 xcode-select 命令行工具设置默认版本。
- 在运行 CMake 和构建工具时,通过设置 DEVELOPER_DIR 环境变量来覆盖默认版本。
为方便起见, cmake-gui 提供了一个环境变量编辑器。
18.2.2 命令行 -G 选项
CMake 默认选择一个基于平台的生成器。通常,默认生成器足以让用户继续构建软件。
用户可以使用 -G 选项覆盖默认生成器:
$ cmake .. -G Ninja
cmake --help 的输出包括一个可供用户选择的生成器列表。注意,生成器名称是区分大小写的。
在类 Unix 系统(包括 Mac OS X )上,默认情况下使用 Unix Makefiles 生成器。该生成器的一个变体也可以在 Windows 上的各种环境中使用,例如 NMake Makefiles 和 MinGW Makefiles 生成器。这些生成器生成一个 Makefile 变体,可以用 make 、 gmake 、 nmake 或类似的工具来执行。有关目标环境和工具的更多信息,请参阅各个生成器文档。
Ninja 生成器可在所有主要平台上使用。 Ninja 是一个用法类似于 make 的构建工具,但更注重性能和效率。
在 Windows 上, cmake 可以用来为 Visual Studio IDE 生成解决方案。 Visual Studio 版本可以由 IDE 的产品名称指定,其中包括一个四位数字的年份。别名也可以使用,有时 Visual Studio 版本的指向 Visual C++ 编译器的产品版本相对应的两个数字,或两者的组合:
$ cmake .. -G "Visual Studio 2019"
$ cmake .. -G "Visual Studio 16"
$ cmake .. -G "Visual Studio 16 2019"
Visual Studio 生成器可以针对不同的体系结构。可以使用 -A 选项指定目标体系结构:
cmake .. -G "Visual Studio 2019" -A x64
cmake .. -G "Visual Studio 16" -A ARM
cmake .. -G "Visual Studio 16 2019" -A ARM64
在 Apple 上, Xcode 生成器可以用来为 Xcode IDE 生成项目文件。
一些 IDE 如 KDevelop4 、 QtCreator 和 CLion对 基于 cmake 的构建系统有原生支持。这些 IDE 提供了用于选择要使用的底层生成器的用户界面,通常是在 Makefile 或基于 Ninja 的生成器之间进行选择。
请注意,在第一次调用 CMake 之后,不可能使用 -G 更改生成器。要更改生成器,必须删除构建目录,并且必须从头开始构建。
当生成 Visual Studio 项目和解决方案文件时,在初始运行 cmake 时可以使用其他几个选项。
Visual Studio 工具集可以用 -T 选项指定:
$ # 使用 clang-cl 工具集构建
$ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T ClangCL
$ # 针对 Windows XP 构建
$ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T v120_xp
-A 选项指定目标体系结构,而 -T 选项可用于指定所使用的工具链的详细信息。例如, -Thost=x64 可用于选择 64 位版本的主机工具。下面演示了如何使用 64 位工具并为 64 位目标体系结构构建:
$ cmake .. -G "Visual Studio 16 2019" -A x64 -Thost=x64
18.2.3 在 cmake-gui 中选择生成器
“配置”按钮会触发一个新的对话框来选择要使用的 CMake 生成器。

命令行上所有可用的生成器也可以在 cmake-gui 中使用。

在选择 Visual Studio 生成器时,可以使用其他选项来设置要为其生成的体系结构。

18.3 设置构建变量
在调用 CMake 时,软件项目通常需要在命令行上设置变量。下表列出了一些最常用的 CMake 变量:
变量 | 含义 |
---|---|
CMAKE_PREFIX_PATH | 搜索依赖包的路径 |
CMAKE_MODULE_PATH | 搜索其他 CMake 模块的路径 |
CMAKE_BUILD_TYPE | 构建配置,例如 Debug 或 Release ,确定调试/优化标志。这只与 Makefile 和 Ninja 等单配置构建系统相关。像 Visual Studio 和 Xcode 这样的多配置构建系统会忽略这个设置。 |
CMAKE_INSTALL_PREFIX | 使用 install 构建目标将软件安装到的位置 |
CMAKE_TOOLCHAIN_FILE | 包含交叉编译数据(如工具链和 sysroots )的文件。 |
BUILD_SHARED_LIBS | 是否为没有类型的 add_library 命令构建共享库而不是静态库 |
CMAKE_EXPORT_COMPILE_COMMANDS | 为基于 clang 的工具生成一个 compile_commands.json 文件 |
可以使用其他特定于项目的变量来控制构建,例如启用或禁用项目的组件。
CMake 没有约定如何在不同的构建系统之间命名这些变量,除了前缀 CMAKE_ 的变量通常指的是 CMake 自己提供的选项,不应该在第三方选项中使用外,(项目中定义的变量)应该使用自己的前缀。 cmake-gui 工具可以以由前缀定义的组来(分组)显示选项,因此第三方确保它们使用一致的前缀是有意义的。
18.3.1 在命令行上设置变量
CMake 变量可以在创建初始构建时在命令行上设置:
$ mkdir build
$ cd build
$ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug
或者在随后调用 cmake 时:
$ cd build
$ cmake . -DCMAKE_BUILD_TYPE=Debug
-U 标志可以用来取消 cmake 命令行上的变量设置:
$ cd build
$ cmake . -UMyPackage_DIR
最初在命令行上创建的 CMake 构建系统可以使用 cmake-gui 进行修改,反之亦然。
cmake 工具允许使用 -C 选项指定用于填充初始缓存的文件。这对于简化重复需要相同缓存项的命令和脚本非常有用。
18.3.2 使用 cmake-gui 设置变量
变量可以在 cmake-gui 中使用“添加项”按钮进行设置。这会触发一个新的对话框来设置变量的值。

cmake-gui 用户界面的主视图可用于编辑现有变量。
18.3.3 CMake 缓存
当 CMake 执行时,它需要找到编译器、工具和依赖项的位置。它还需要能够一致地重新生成一个构建系统,以使用相同的编译/链接标志和依赖项的路径。用户还需要对这些参数进行配置,因为它们是特定于用户系统的路径和选项。
当它第一次执行时, CMake 在构建目录中生成一个 CMakeCache.txt 文件,其中包含这些产物的键值对。用户可以通过运行 cmake-gui 或 ccmake 工具查看或编辑缓存文件。这些工具提供了一个交互界面,用于重新配置所提供的软件和重新生成构建系统,这是在编辑缓存值之后所需要的。每个缓存项可能有一个相关的简短帮助文本,它显示在用户界面工具中。
缓存项也可以有一个类型来表示它应该如何在用户界面中显示。例如, BOOL 类型的缓存项可以通过用户界面中的复选框进行编辑, STRING 可以在文本字段中进行编辑,而 FILEPATH 虽然类似于 STRING ,但也应该提供一种使用文件对话框定位文件系统路径的方法。 STRING 类型的项可以提供一个允许值的限制列表,然后在 cmake-gui 用户界面的下拉菜单中以供用户选择(请参阅 STRINGS 缓存属性)。
软件包附带的 CMake 文件也可以使用 option 命令定义布尔切换选项。该命令创建一个缓存项,其中包含帮助文本和默认值。这样的缓存项通常是特定于所提供的软件的,并且会影响构建的配置,例如是否构建测试和示例,是否在启用异常的情况下构建等等。
18.4 预设
CMake 能解析一个文件,CMakePresets.json CMakeUserPresets.json ,以及它的用户特定的对应项 CMakeUserPresets.json ,用于保存常用配置设置的预设。这些预设可以设置构建目录、生成器、缓存变量、环境变量和其他命令行选项。所有这些选项都可以被用户覆盖。 CMakePresets.json的 格式的全部细节在 cmake-presets 手册中列出。
18.4.1 在命令行上使用预设
当使用 cmake 命令行工具时,可以通过使用 --preset 选项调用预设。如果指定了 --preset ,则不需要生成器和构建目录,但可以指定它们来覆盖它们。例如,如果你有以下 CMakePresets.json 文件:
{
"version": 1,
"configurePresets": [
{
"name": "ninja-release",
"binaryDir": "${sourceDir}/build/${presetName}",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}
然后运行下面的命令:
cmake -S /path/to/source --preset=ninja-release
这将在 /path/to/source/build/ninja-release 中生成一个带有 Ninja 生成器的构建目录,并将 CMAKE_BUILD_TYPE 设置为 Release 。
如果你想查看可用预设的列表,你可以运行:
cmake -S /path/to/source --list-presets
这将列出 /path/to/source/CMakePresets 和 /path/to/source/CMakeUsersPresets.json 中可用的预置,而不生成构建树。
18.4.2 在 cmake-gui 中使用预设
如果一个项目有可用的预置,要么通过 CMakePresets.json ,要么通过 CMakeUserPresets.json 。在 cmake-gui 中,预设列表将出现在源码目录和二进制目录之间的下拉菜单中。选择预设将设置二进制目录、生成器、环境变量和缓存变量,但是在选择预设后可以覆盖所有这些选项。
18.5 调用构建系统
在生成构建系统之后,可以通过调用特定的构建工具来构建软件。在使用 IDE 生成器的情况下,这可能涉及将生成的项目文件加载到 IDE 中以调用构建。
CMake 知道调用构建所需的特定构建工具,所以一般来说,要在生成后从命令行构建构建系统或项目,可以在 build 目录中调用以下命令:
$ cmake --build .
–build 标志为 cmake 工具启用一种特定的操作模式。它调用与[生成器](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#manual:cmake-generators(7)关联的 CMAKE_MAKE_PROGRAM 命令,或者由用户配置的构建工具。
–build 模式还接受参数 --target 来指定要构建的特定目标,例如特定库、可执行目标或自定义目标,或者特定的特殊目标,如 install :
$ cmake --build . --target myexe
在多配置生成器的情况下, --build 模式也接受 --config 参数来指定要构建的特定配置:
$ cmake --build . --target myexe --config Release
如果生成器生成一个特定于使用 CMAKE_BUILD_TYPE 变量调用 cmake 时选择的配置的构建系统,那么 --config 选项不起作用。
一些构建系统忽略了在构建过程中调用的命令行细节。可以使用 --verbose 标志来显示这些命令行:
$ cmake --build . --target myexe --verbose
–build 模式还可以通过在 – 之后列出特定的命令行选项,将它们传递给底层构建工具。这对于为构建工具指定选项非常有用。例如在作业失败后继续构建,而 CMake 并不为此提供高级用户界面。
对于所有生成器,可以在调用 CMake 后运行底层构建工具。例如,可以在 Unix 的 Makefiles 生成器生成后执行 make 以调用构建,可以在使用 Ninja 生成器生成后执行 ninja 等等。 IDE 构建系统通常也提供命令行工具来构建项目。
18.5.1 选择目标
CMake 文件中描述的每个可执行文件和库都是一个构建目标,并且构建系统可以描述自定义目标,或者用于内部使用,或者用于用户消费,例如创建文档。
CMake 为所有提供 CMake 文件的构建系统提供了一些内置目标。
all
Makefile 和 Ninja 生成器使用的默认目标。构建构建系统中的所有目标,除了那些被 EXCLUDE_FROM_ALL 目标属性或 EXCLUDE_FROM_ALL 目录属性排除的目标。在 Xcode 和 Visual Studio 生成器中该目标名称为 ALL_BUILD 。
help
列出可用于构建的目标。当使用 Unix Makefiles 或 Ninja 生成器时,可以使用该目标,并且其输出是随特定工具(而不同)的。
clean
删除构建的目标文件和其他输出文件。基于 Makefile 的生成器为每个目录创建一个 claen 目标,这样就可以清理单个目录。 Ninja 工具提供了自己颗粒度的 -t clean 系统。
test
运行测试。只有当 CMake 文件提供基于 ctest 的测试时,此目标才会自动可用。另请参见运行测试。
install
安装软件。只有当软件使用 install 命令定义安装规则时,这个目标才会自动可用。另请参见软件安装。
package
创建一个二进制包。只有当 CMake 文件提供了基于 cpack 的包时,这个目标才会自动可用。
package_source
创建一个源码包。只有当 CMake 文件提供了基于 cpack 的包时,这个目标才会自动可用。
对于基于 Makefile 的系统,提供了二进制构建目标的 /fast 变体。 /fast 变体用于构建指定的目标,而不考虑其依赖关系。依赖项不会被检查,如果过期也不会重新构建。 Ninja 生成器在进行依赖项检查时足够快,是因为这样的目标没有提供给该生成器。
基于 Makefile 的系统还提供了构建目标来预处理、组装和编译特定目录中的单个文件。
$ make foo.cpp.i
$ make foo.cpp.s
$ make foo.cpp.o
文件扩展名内置于目标的名称中,因为可能存在具有相同名称但扩展名不同的另一个文件。但是,还提供了没有文件扩展名的构建目标。
$ make foo.i
$ make foo.s
$ make foo.o
在包含 foo.c 和 foo.cpp 的构建系统中构建 foo 目标将预处理这两个文件。
18.5.2 指定构建程序
–build 模式调用的程序由 CMAKE_MAKE_PROGRAM 变量决定。对于大多数生成器,不需要配置特定的程序。
生成器 | 默认构建程序 | 替代选择 |
---|---|---|
XCode | xcodebuild | |
Unix Makefiles | make | |
NMake Makefiles | make | jom |
NMake Makefiles JOM | jom | nmake |
MinGW Makefiles | mingw32-make | |
MSYS Makefiles | make | |
Ninja | ninja | |
Visual Studio | msbuild | |
Watcom WMake | wmake |
jom 工具能够读取 NMake 风格的 make 文件并并行构建,而 NMake 工具总是串行构建。在使用 NMake Makefiles 生成器生成后,用户可以运行 jom 而不是 NMake 。如果在使用 NMake Makefiles 生成器时将 CMAKE_MAKE_PROGRAM 设置为 jom ,那么 --build 模式也会使用 jom ,并且为了方便,提供了 NMake Makefiles JOM 生成器以正常方式查找 jom 并将其用作 CMAKE_MAKE_PROGRAM 。为了完整起见, nmake 是一个可选的工具,它可以处理 NMake Makefiles JOM 生成器的输出,但这样做将是一种悲伤(应该是不推荐的意思)。
18.6 软件安装
CMAKE_INSTALL_PREFIX 变量可以在 CMake 缓存中设置,以指定安装所提供软件的位置。如果提供的软件具有使用 install 命令指定的安装规则,它们将把产物安装到该前缀中。在 Windows 上,默认安装位置对应于 ProgramFiles 系统目录,该目录可能是特定于体系结构的。在 Unix 主机上, /usr/local 是默认的安装位置。
CMAKE_INSTALL_PREFIX 变量总是指向目标文件系统上的安装前缀。
在交叉编译或打包场景中, sysroot 是只读的,或者 sysroot 应该保持原始状态,可以将 CMAKE_STAGING_PREFIX 变量设置为实际安装文件的位置。
命令:
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_SYSROOT=$HOME/root \
-DCMAKE_STAGING_PREFIX=/tmp/package
$ cmake --build .
$ cmake --build . --target install
会导致文件被安装到 /tmp/package/lib/libfoo.so 等路径。主机上的 /usr/local 位置不受影响。
一些提供的软件可能会指定卸载规则,但 CMake 本身默认不生成这样的规则。
18.7 运行测试
CMake 发行版附带了 ctest 工具,用于执行提供的测试并报告结果。提供了 test 构建目标来运行所有可用的测试,但是 ctest 工具允许对运行哪些测试、如何运行它们以及如何报告结果进行粒度控制。在构建目录中执行 ctest 相当于运行 test 目标:
$ ctest
可以传递正则表达式以仅运行与该表达式匹配的测试。要只运行名称中包含 Qt 的测试:
$ctest-R Qt
正则表达式也可以排除测试。要只运行名称中没有 Qt 的测试:
$ctest-E Qt
通过向 ctest 传递 -j 参数,可以并行运行测试:
$ctest-R Qt-j8
也可以设置环境变量 CTEST_PARALLEL_LEVEL ,以避免传递 -j 。
默认情况下, ctest 不打印测试的输出。命令行参数 -V (或 --verbose )启用详细模式以打印所有测试的输出。 --output-on-failure 选项仅打印失败测试的测试输出。环境变量 CTEST_OUTPUT_ON_FAILURE 可以设置为 1 ,作为将 --output-on-failure 选项传递给 ctest 的替代方法。