CMake 完全解析:用户交互指南
0. 引言
如果软件包为基于CMake的构建系统提供了软件源,则软件的使用者需要运行CMake用户交互工具来构建它。
行为良好的基于CMake的构建系统不会在源目录中创建任何输出,因此通常,用户会执行源外构建并在那里执行构建。首先,必须指示CMake生成合适的buildsystem,然后用户调用构建工具来处理生成的buildsystem。生成的buildsystem特定于用于生成它的计算机,不可再发行。提供的源软件包的每个使用者都需要使用CMake生成特定于其系统的buildsystem。
生成的构建系统通常应被视为只读的。作为主要工件的CMake文件应该完全指定buildsystem,并且没有理由在IDE中手动填充属性,例如在生成buildsystem之后。CMake将定期重写生成的buildsystem,因此用户的修改将被覆盖。
通过提供CMake文件,本手册中描述的特性和用户界面可用于所有基于CMake的构建系统。
在处理提供的CMake文件时,CMake工具可能会向用户报告错误,例如报告编译器不受支持,或者编译器不支持所需的编译选项,或者找不到依赖项。这些错误必须由用户通过选择不同的编译器、安装依赖项或指示CMake在何处找到它们等来解决。
0.1 命令行cmake工具
cmake(1) 与新的软件源代码副本的一个简单但典型的用法是创建一个构建目录并在那里调用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工具可能会报告针对软件提供商的警告,而不是针对软件使用者的警告。此类警告以“此警告针对项目开发人员”结尾。用户可以通过将-Wno-dev
标志传递给cmake(1)来禁用此类警告。
0.2 cmake gui工具
更习惯于GUI界面的用户可以使用cmakegui(1)工具来调用cmake并生成buildsystem。
必须首先设置源代码路径和二进制目标代码路径。通常建议对源代码和生成使用不同的目录。
1. 生成 Buildsystem
有几种用户界面工具可用于从CMake文件生成 buildsystem。ccmake(1) 和cmake-gui(1) 工具指导用户设置各种必要的选项。可以调用cmake(1)工具在命令行上指定选项。本手册描述了可使用任何用户界面工具设置的选项,尽管每个工具的设置模式不同。
1.1 命令行环境
使用Makefiles或Ninja等命令行构建系统调用cmake(1)时,必须使用正确的构建环境以确保构建工具可用。CMake必须能够根据需要找到合适的构建工具、编译器、链接器和其他工具。
在Linux系统上,通常在系统范围内的位置提供适当的工具,并且可以通过系统包管理器轻松安装。也可以使用用户提供的或安装在非默认位置的其他工具链。
交叉编译时,有些平台可能需要设置环境变量,或者提供脚本来设置环境。
Visual Studio 提供多个命令提示和 vcvarsall.bat
批处理脚本为命令行 buildsystem 设置正确环境。虽然在使用Visual Studio生成器时不一定要使用相应的命令行环境,但这样做没有缺点。
使用Xcode时,可以安装多个Xcode版本。可以通过多种不同的方式选择要使用的方法,但最常用的方法是:
- 在Xcode IDE的首选项中设置默认版本。
- 通过xcode select命令行工具设置默认版本。
- 在运行CMake和构建工具时,通过设置DEVELOPER\u DIR环境变量来覆盖默认版本。
为了方便起见,cmakegui(1) 提供了一个环境变量编辑器。
1.2 命令行-G选项
CMake默认根据平台选择生成器。通常,默认生成器足以允许用户继续构建软件。
用户可以使用-G选项覆盖默认生成器:
$ cmake .. -G Ninja
cmake–help的输出包括一个可供用户选择的生成器列表。请注意,生成器名称区分大小写。
在类Unix系统(包括macosx)上,默认情况下使用Unix Makefiles生成器。该生成器的一个变体也可以在各种环境中的Windows上使用,例如NMake Makefiles和MinGW Makefiles生成器。这些生成器生成一个Makefile变量,可以使用make、gmake、nmake或类似工具执行。有关目标环境和工具的更多信息,请参阅单个生成器文档。
忍者发生器可在所有主要平台上使用。ninja是一个构建工具,在用例中与make类似,但是它关注性能和效率。
在Windows上,可以使用cmake(1)为visualstudioide生成解决方案。visualstudio版本可以由IDE的产品名指定,其中包括四位数的年份。别名用于有时引用Visual Studio版本的其他方式,例如与VisualC++编译器的产品版本相对应的两个数字,或两者的组合:
$ 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(1)时,可以使用其他几个选项。
可以使用-T选项指定Visual Studio工具集:
$ # Build with the clang-cl toolset
$ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T ClangCL
$ # Build targeting Windows XP
$ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T v120_xp
虽然-A选项指定了\u目标\u体系结构,但-T选项可用于指定所用工具链的详细信息。例如,可以指定-Thost=x64来选择主机工具的64位版本。下面演示如何使用64位工具,以及如何为64位目标体系结构构建:
$ cmake .. -G "Visual Studio 16 2019" -A x64 -Thost=x64
1.3 在cmake gui中选择生成器
“Configure”(配置)按钮触发一个新对话框,以选择要使用的CMake生成器。
命令行上可用的所有生成器在cmake gui(1)中也可用。
选择 Visual Studio 生成器时,可以使用更多选项来设置要为其生成的体系结构。
2. 设置生成变量
在调用CMake时,软件项目通常需要在命令行上设置变量。下表列出了一些最常用的CMake变量:
变量 | 用途 |
---|---|
CMAKE_PREFIX_PATH | 搜索依赖包的路径 |
CMAKE_MODULE_PATH | 搜索其他CMake模块的路径 |
CMAKE_BUILD_TYPE | 构建配置,例如调试或发布,确定调试/优化标志。这只与单个配置构建系统(如Makefile和Ninja)相关。多配置构建系统(如Visual Studio和Xcode的构建系统)忽略此设置。 |
CMAKE_INSTALL_PREFIX | 将软件安装到安装生成目标的位置 |
CMAKE_TOOLCHAIN_FILE | 包含交叉编译数据(如工具链和系统根)的文件。 |
BUILD_SHARED_LIBS | 是否为在没有类型的情况下使用的add_library()命令生成共享库而不是静态库 |
CMAKE_EXPORT_COMPILE_COMMANDS | 基于 C 语言工具,生成一个 compile_commands.json 文件 |
其他特定于项目的变量可以用于控制生成,例如启用或禁用项目的组件。
CMake没有规定在提供的不同构建系统之间如何命名这些变量的约定,只是前缀为CMake的变量通常指的是CMake本身提供的选项,不应在第三方选项中使用,而第三方选项应使用自己的前缀。cmakegui(1)工具可以在由前缀定义的组中显示选项,因此第三方确保使用自一致的前缀是有意义的。
2.1 在命令行上设置变量
创建初始生成时,可以在命令行上设置CMake变量:
$ mkdir build
$ cd build
$ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug
或者稍后调用cmake(1):
$ cd build
$ cmake . -DCMAKE_BUILD_TYPE=Debug
-U标志可用于在 cmake(1) 命令行上取消设置变量:
$ cd build
$ cmake . -UMyPackage_DIR
最初在命令行上创建的 CMake buildsystem 可以使用 cmake-gui(1) 进行修改,反之亦然。
cmake(1) 工具允许使用-C选项指定用于填充初始缓存的文件。这对于简化重复需要相同缓存项的命令和脚本非常有用。
2.2 使用 cmake-gui 设置变量
可以使用“添加条目”按钮在cmake gui中设置变量。这将触发一个新对话框来设置变量的值。
cmake-gui(1)用户界面的主视图可用于编辑现有变量。
3. CMake缓存
当执行CMake时,它需要找到编译器、工具和依赖项的位置。它还需要能够一致地重新生成buildsystem,以使用相同的编译/链接标志和依赖项路径。用户还需要配置这些参数,因为它们是特定于用户系统的路径和选项。
当它第一次执行时,CMake生成一个CMakeCache.txt文件构建目录中包含此类工件的键值对的文件。用户可以通过运行cmake-gui(1) 或 ccmake(1) 工具来查看或编辑缓存文件。这些工具提供了一个交互界面,用于在编辑缓存值之后重新配置所提供的软件和重新生成buildsystem。每个缓存条目可能都有一个相关的简短帮助文本,显示在用户界面工具中。
缓存条目也可以有一个类型来表示它应该如何在用户界面中显示。例如,BOOL类型的缓存条目可以由用户界面中的复选框编辑,字符串可以在文本字段中编辑,而FILEPATH虽然类似于字符串,但也应该提供使用文件对话框定位文件系统路径的方法。STRING类型的条目可以提供允许值的限制列表,这些值随后在 cmake-gui(1) 用户界面的下拉菜单中提供(请参阅STRINGS cache属性)。
软件包附带的CMake文件还可以使用 option() 命令定义布尔切换选项。该命令创建一个缓存条目,其中包含帮助文本和默认值。这种缓存项通常特定于所提供的软件,并影响构建的配置,例如是否构建测试和示例,是否在启用异常的情况下构建等等。
3.1 预设
CMake理解一个文件,CMakePresets.json文件,及其特定于用户的对应项,CMakeUserPresets.json文件,用于保存常用配置设置的预设。这些预置可以设置生成目录、生成器、缓存变量、环境变量和其他命令行选项。用户可以覆盖所有这些选项。完整的细节CMakePresets.json文件cmake预设(7) 手册中列出了格式。
3.2 在命令行上使用预设
使用 cmake(1) 命令行工具时,可以使用 --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
这将使用ninja生成器在/path/to/source/build/ninja release中生成一个build目录,并将CMAKE\u build\u TYPE设置为release。
如果要查看可用预设的列表,可以运行:
cmake -S /path/to/source --list-presets
这将列出 /path/to/source
中可用的预设/CMakePresets.json文件和/路径/到/源/CMakeUsersPresets.json文件不生成生成树。
4. 在cmake-gui中使用预设
如果项目具有可用的预设,则可以通过CMakePresets.json文件或者CMakeUserPresets.json文件,预设列表将出现在cmake gui(1)的下拉菜单中,位于源目录和二进制目录之间。选择预设可设置二进制目录、生成器、环境变量和缓存变量,但在选择预设后,可以覆盖所有这些选项。
4.1 调用Buildsystem
生成buildsystem之后,可以通过调用特定的构建工具来构建软件。对于IDE生成器,这可能涉及将生成的项目文件加载到IDE中以调用构建。
CMake知道调用生成所需的特定生成工具,因此一般来说,要从命令行生成生成系统或项目,可以在生成目录中调用以下命令:
$ cmake --build .
–build 标志为 cmake(1) 工具启用特定的操作模式。它调用与生成器关联的CMAKE_MAKE_PROGRAM
命令,或用户配置的构建工具。
–build 模式还接受参数–target来指定要生成的特定目标,例如特定库、可执行文件或自定义目标,或者特定的特定目标,如install:
$ cmake --build . --target myexe
对于多配置生成器,–build模式还接受–config参数,以指定要生成的特定配置:
$ cmake --build . --target myexe --config Release
如果生成器生成特定于某个配置的buildsystem,而该配置是在使用CMAKE_BUILD_TYPE
变量调用cmake时选择的,则–config选项无效。
一些构建系统忽略了在构建过程中调用的命令行的细节。–verbose标志可用于显示以下命令行:
$ cmake --build . --target myexe --verbose
–build模式还可以通过在–之后列出特定的命令行选项,将它们传递给底层构建工具。这对于指定构建工具的选项非常有用,例如在作业失败后继续构建,而CMake不提供高级用户界面。
对于所有生成器,可以在调用CMake之后运行底层构建工具。例如,make可以在使用Unix Makefiles生成器生成后执行以调用构建,或者在使用ninja生成器生成后执行ninja等。IDE构建系统通常提供用于构建也可以调用的项目的命令行工具。
4.2 选择目标
CMake文件中描述的每个可执行文件和库都是构建目标,构建系统可以描述自定义目标,供内部使用,或者供用户使用,例如用于创建文档。
CMake为所有提供CMake文件的构建系统提供了一些内置目标。
-
all
Makefile和忍者生成器使用的默认目标。生成buildsystem中的所有目标,但被其EXCLUDE\u FROM\u all target属性或EXCLUDE\u FROM\u all directory属性排除的目标除外。在Xcode和visualstudio生成器中使用ALL\u BUILD这个名称。 -
help
列出可用于生成的目标。这个目标在使用Unix Makefiles或Ninja生成器时可用,并且确切的输出是特定于工具的。 -
clean
删除生成的对象文件和其他输出文件。基于Makefile的生成器为每个目录创建一个干净的目标,以便可以清理单个目录。忍者工具提供了自己的颗粒-t清洁系统。 -
test
运行测试。只有当CMake文件提供基于CTest的测试时,此目标才自动可用。另请参见运行测试。 -
install
安装软件。只有软件使用install()命令定义安装规则时,此目标才会自动可用。另请参见软件安装。 -
package
创建二进制包。只有当CMake文件提供基于CPack的包时,此目标才自动可用。 -
package_source
创建源程序包。只有当CMake文件提供基于CPack的包时,此目标才自动可用。
对于基于Makefile的系统,提供了二进制构建目标的/fast变体。/fast变量用于构建指定的目标,而不考虑其依赖性。依赖项不会被检查,如果过期也不会重建。忍者生成器在依赖性检查方面足够快,以确保没有为该生成器提供此类目标。
基于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.i目标将预处理这两个文件。
5. 指定生成程序
–build模式调用的程序由CMAKE\u MAKE\u程序变量确定。对于大多数生成器,不需要配置特定的程序。
生成器 | 默认生成程序 | 选择 |
---|---|---|
XCode | xcodebuild | |
Unix Makefiles | make | |
NMake Makefiles | nmake | jom |
NMake Makefiles JOM | jom | nmake |
MinGW Makefiles | mingw32-make | |
MSYS Makefiles | make | |
Ninja | ninja | |
Visual Studio | msbuild | |
Watcom WMake | wmake |
jom工具能够读取NMake风格的makefile并并行构建,而NMake工具总是串行构建。使用NMake Makefiles生成器生成后,用户可以运行jom而不是NMake。如果在使用NMake-Makefiles生成器时将CMAKE\u MAKE\u程序设置为jom,那么–build模式也将使用jom,并且为了方便起见,提供了NMake-Makefiles jom生成器以正常方式查找jom并将其用作CMAKE_MAKE_PROGRAM。为了完整性,nmake是一个替代工具,它可以处理nmake Makefiles JOM生成器的输出,但这样做会让人感到悲观。
6. 软件安装
可以在CMAKE缓存中设置CMAKE\u INSTALL\u PREFIX变量,以指定在何处安装提供的软件。如果提供的软件具有使用install()命令指定的安装规则,则它们将在该前缀中安装工件。在Windows上,默认安装位置对应于ProgramFiles系统目录,该目录可能是特定于体系结构的。在Unix主机上,/usr/local是默认的安装位置。
CMAKE\u INSTALL\u PREFIX变量始终引用目标文件系统上的安装前缀。
在系统根为只读或系统根应保持原始的交叉编译或打包方案中,可以将CMAKE\u STAGING\u 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默认情况下不会生成此类规则。
7. 运行测试
ctest(1) 工具随CMake发行版一起提供,用于执行提供的测试并报告结果。提供测试构建目标来运行所有可用的测试,但是ctest(1) 工具允许对要运行的测试、如何运行测试以及如何报告结果进行精确控制。在build目录中执行ctest(1) 相当于运行测试目标:
$ ctest
可以传递正则表达式以仅运行与该表达式匹配的测试。要仅运行名称为Qt的测试,请执行以下操作:
$ ctest -R Qt
正则表达式也可以排除测试。要仅运行名称中没有Qt的测试,请执行以下操作:
$ ctest -E Qt
通过将-j参数传递给ctest(1),可以并行运行测试:
$ ctest -R Qt -j8
也可以设置环境变量CTEST_PARALLEL_LEVEL,以避免传递-j。
默认情况下,ctest(1) 不打印测试的输出。命令行参数-V(或–verbose)允许verbose模式打印所有测试的输出。--output-on-failure
选项只打印失败测试的测试输出。除了将--output-on-failure
选项传递给CTEST(1),环境变量 CTEST_OUTPUT_ON_FAILURE
可以设置为 1。
【参考资料】