CMake 入门/Out-of-source Build

CMake 如何决定目录 编辑

CMake 的参数格式如下

cmake [選項] <source tree 根目錄>
cmake [選項] <binary tree 根目錄>

在 CMake 命令列最后一项所指定的路径将被视为 source tree 根目录,当其他选项缺省时此目录为必要参数。若命令列没有给定路径 CMake 才会将目前工作资料夹当成 source tree 根目录。 source tree 根目录必须含有 CMakeLists.txt ,否则会发生错误。

另外,当命令列指定的路径下含有 CMakeCache.txt 时(通常是前次建置时遗留下的),该路径也会被当成 binary tree 根目录,否则 CMake 一律会把目前工作资料夹当成 binary tree 根目录。

取得路径资讯 编辑

CMake 提供了几个变数让使用者在撰写 CMakeLists 时取得路径资讯,这里先介绍其中几个:

CMAKE_SOURCE_DIR
内容为 source tree 根目录的完整路径,也就是 CMake 开始建置过程的进入点。
CMAKE_BINARY_DIR
内容为 binary tree 根目录的完整路径,在 in-source build 的时候值与 CMAKE_SOURCE_DIR 相同。
PROJECT_SOURCE_DIR
目前所属专案的原始码根目录,即内含 project() 指令的 CMakeLists 所在资料夹。前面的例子没有阶层之分,所以 PROJECT_SOURCE_DIR 和 CMAKE_SOURCE_DIR 相同;更复杂的专案会包含数个子专案,子专案下面还可能会有多个资料夹,PROJECT_SOURCE_DIR 内容为目前正在处理中的专案最上层目录。
PROJECT_BINARY_DIR
目前所属专案的建置根目录,专案意义同上。在 in-source build 时和 PROJECT_SOURCE_DIR 相同。
CMAKE_CURRENT_SOURCE_DIR
目前正在处理的 CMakeLists.txt 所在位置。
CMAKE_CURRENT_BINARY_DIR
目前正在处理的 CMakeLists.txt 对应的建置资料夹位置。当然,在 in-source build 时和 CMAKE_CURRENT_SOURCE_DIR 相同。

这里要注意的是,CMake 中都使用绝对路径来表示档案位置。

为了了解 CMake 目前的 source tree 和 binary tree 为何,我们可以在 CMakeLists 当中加上:

message("CMAKE_SOURCE_DIR= ${CMAKE_SOURCE_DIR}")
message("CMAKE_BINARY_DIR= ${CMAKE_BINARY_DIR}")

在源码之外建置 编辑

本章采用和之前相同的范例,目录树的架构如下,各原始码的内容请参考前一节--建置基本的执行档

  • ex2/
    • src/
      • CMakeLists.txt
      • calc.c
      • calc.h
      • main.c


Note
若是沿用前一个例子的档案,请先清除源码根目录所有CMake 中间档,否则源码根目录含有前次留下的 CMakeCache.txt,仍会被 CMake 优先视为建置根目录,于是执行 In-source build


设目前工作目录为 ex2/,执行下列指令:

$ mkdir -p build
$ cd build
$ cmake ../src
$ make

如果你的编译器并非系统预设,别忘了依照需求指定 Generator:

$ cmake -G "Unix Makefiles" ../src
$ cmake -G "MSYS Makefiles" ../src
> cmake -G "Visual Studio 9 2008" ../src


执行结束后,ex2/build 下会出现各项中间档、makefile 以及最终的 ex2 执行档,但 ex2/src 原封不动,只有三个 C 源码和一个 CMakeLists.txt。之后若出现什么疑难杂症,可以轻松将 ex2/build 砍掉重练。

注意事项 编辑

在执行 Out-of-source build 之前必须先确定所指定的源码根目录是否干净,若是该目录下含有前次留下的 CMakeCache.txt 仍会执行 In-source build。

由于 CMake 生成的 makefile 当中并不会包含 make distclean 的 rule,因此强烈建议采用 out-of-source build,发布的时候只需将干净的 source tree 打包即可。