运行 CMake

在编写 CMake 之前,要确保你已经清楚了如何运行 CMake 来构建文件。 几乎所有 CMake 项目都一样。

构建项目

除非另行说明,你始终应该建立一个专用于构建的目录并在那里构建项目。从技术上来讲,你可以进行内部构建(即在源代码目录下执行 CMake 构建命令),但是必须注意不要覆盖文件或者把它们添加到 git,所以别这么做就好。

这是经典的 CMake 构建流程 (TM):

  1. ~/package $ mkdir build
  2. ~/package $ cd build
  3. ~/package/build $ cmake ..
  4. ~/package/build $ make

你可以用 cmake --build . 替换 make 这一行。它会调用 make 或这任何你正在使用的构建工具。如果你正在使用版本比较新的 CMake(除非你正在检查对于老版本 CMake 的兼容性,否则应该使用较新的版本),你也可以这样做:

  1. ~/package $ cmake -S . -B build
  2. ~/package $ cmake --build build

以下任何一条命令都能够执行安装:

  1. # From the build directory (pick one)
  2. ~/package/build $ make install
  3. ~/package/build $ cmake --build . --target install
  4. ~/package/build $ cmake --install . # CMake 3.15+ only
  5. # From the source directory (pick one)
  6. ~/package $ make -C build install
  7. ~/package $ cmake --build build --target install
  8. ~/package $ cmake --install build # CMake 3.15+ only

所以你应该选择哪一种方法?只要你别忘记输入构建目录作为参数,在构建目录之外的时间较短,并且从源代码目录更改源代码比较方便就行。你应该试着习惯使用 --build,因为它能让你免于只用 make 来构建。需要注意的是,在构建目录下进行工作一直都非常普遍,并且一些工具和命令(包括 CTest)仍然需要在 build 目录中才能工作。

额外解释一下,你可以指定 CMake 工作在来自构建目录的源代码目录,也可以工作在任何现有的构建目录。

如果你使用 cmake --build 而不是直接调用更底层的构建系统(译者注:比如直接使用 make),你可以用 -v 参数在构建时获得详细的输出(CMake 3.14+),用 -j N 指定用 N 个 CPU 核心并行构建项目(Cmake 3.12+),以及用 --target(任意版本的 CMake)或 -t(CMake 3.15+)来选择一个目标进行部分地构建。这些命令因不同的构建系统而异,例如 VERBOSE=1 makeninja -v。你也可以使用环境变量替代它们,例如 CMAKE_BUILD_PARALLEL_LEVEL (CMake 3.12+) 和 VERBOSE (CMake 3.14+)。

指定编译器

指定编译器必须在第一次运行时在空目录中进行。这种命令并不属于 CMake 语法,但你仍可能不太熟悉它。如果要选择 Clang:

  1. ~/package/build $ CC=clang CXX=clang++ cmake ..

这条命令设置了 bash 里的环境变量 CC 和 CXX,并且 CMake 会使用这些参数。这一行命令就够了,你也只需要调用一次;之后 CMake 会继续使用从这些变量里推导出来的路径。

指定生成器

你可以选择的构建工具有很多;通常默认的是 make。要显示在你的系统上 CMake 可以调用的所有构建工具,运行:

  1. ~/package/build $ cmake --help

你也可以用 -G"My Tool"(仅当构建工具的名字中包含空格时才需要引号)来指定构建工具。像指定编译器一样,你应该在一个目录中第一次调用 CMake 时就指定构建工具。如果有好几个构建目录也没关系,比如 build/buildXcode。你可以用环境变量 CMAKE_GENERATOR 来指定默认的生成器(CMake 3.15+)。需要注意的是,makefiles 只会在你明确地指出线程数目之时才会并行运行,比如 make -j2,而 Ninja 却会自动地并行运行。在较新版本的 CMake 中,你能直接传递并行选项,比如-j2,到命令 cmake --build

设置选项

在 CMake 中,你可以使用 -D 设置选项。你能使用 -L 列出所有选项,或者用 -LH 列出人类更易读的选项列表。如果你没有列出源代码目录或构建目录,这条命令将不会重新运行 CMake(使用 cmake -L 而不是 cmake -L .)。

详细和部分的构建

同样,这不属于 CMake,如果你正使用像 make 一样的命令行构建工具,你能获得详细的输出:

  1. ~/package/build $ VERBOSE=1 make96
  2. 我们已经提到了在构建时可以有详细输出,但你也可以看到详细的 CMake 配置输出。`--trace` 选项能够打印出运行的 CMake 的每一行。由于它过于冗长,CMake 3.7 添加了 `--trace-source="filename"` 选项,这让你可以打印出你想看的特定文件运行时执行的每一行。如果你选择了要调试的文件的名称(在调试一个 CMakeLists.txt 时通常选择父目录,因为它们名字都一样),你就会只看到这个文件里运行的那些行。这很实用!

实际上你写成 make VERBOSE=1,make 也能正确工作,但这是 make 的一个特性而不是命令行的惯用写法。

你也可以通过指定一个目标来仅构建一部分,例如指定你已经在 CMake 中定义的库或可执行文件的名称,然后 make 将会只构建这一个目标。

选项

CMake 支持缓存选项。CMake 中的变量可以被标记为 “cached”,这意味着它会被写入缓存(构建目录中名为 CMakeCache.txt 的文件)。你可以在命令行中用 -D 预先设定(或更改)缓存选项的值。CMake 查找一个缓存的变量时,它就会使用已有的值并且不会覆盖这个值。

标准选项

大部分软件包中都会用到以下的 CMake 选项:

  • -DCMAKE_BUILD_TYPE= 从 Release, RelWithDebInfo, Debug, 或者可能存在的更多参数中选择。
  • -DCMAKE_INSTALL_PREFIX= 这是安装位置。UNIX 系统默认的位置是 /usr/local,用户目录是 ~/.local,也可以是你自己指定的文件夹。
  • -DBUILD_SHARED_LIBS= 你可以把这里设置为 ONOFF 来控制共享库的默认值(不过,你也可以明确选择其他值而不是默认值)
  • -DBUILD_TESTING= 这是启用测试的通用名称,当然不会所有软件包都会使用它,有时这样做确实不错。

调试你的 CMake 文件

我们已经提到了在构建时可以有详细输出,但你也可以看到详细的 CMake 配置输出。--trace 选项能够打印出运行的 CMake 的每一行。由于它过于冗长,CMake 3.7 添加了 --trace-source="filename" 选项,这让你可以打印出你想看的特定文件运行时执行的每一行。如果你选择了要调试的文件的名称(在调试 CMakeLists.txt 时通常选择父目录,因为它的名字在任何项目中都一样),你就会只看到这个文件里运行的那些行。这很实用!