BLOG

Record, summarize, and improve.

CMake

介绍

「CMake」这个名字是"Cross platform Make"的缩写。虽然名字中含有"make",但是CMake和Unix上常见的「make」系统是分开的,而且更为高阶。特点

  • 支持分布式构建(在多台电脑上同时构建)
  • 在许多作业系统上进行跨平台编译,包括 Linux、与POSIX相容的系统(AIX、*BSD系统、HP-UX、IRIX、MinGW/MSYS、Solaris)、Mac OS X和微软Windows 95/98/NT/2000/XP等。
  • 产生可以给Graphviz用的全局相依图

cmake_tutorial

CMake命令

CMake 默认根据平台选择一个生成器。通常,默认生成器足以让用户继续构建软件。用户可以使用以下选项覆盖默认生成器-G

$ cmake .. -G Ninja的输出包括列表 cmake --helpgenerators可供用户选择。请注意,生成器名称区分大小写。

在类 Unix 系统(包括 Mac OS X)上, Unix Makefiles默认情况下使用生成器。该生成器的一个变体也可以在 Windows 上的各种环境中使用,例如 NMake Makefiles和 MinGW Makefiles发电机。这些生成器生成Makefile可以使用makegmakenmake类似工具执行的变体。有关目标环境和工具的更多信息,请参阅各个生成器文档。

Ninja生成器在所有主要平台上都可用。ninja是一个在用例上与类似的构建工具make,但侧重于性能和效率。

-A选项指定了 _target_ 体系结构,但该-T选项可用于指定所用工具链的详细信息。

命令行上设置 CMake 变量

mkdir build
$ cd build
$ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug

-U标志可用于命令行取消设置变量

cd build
$ cmake . -UMyPackage_DIR

用选项-C指定一个文件来填充初始缓存

CMake变量

软件项目通常需要在调用 CMake 时在命令行上设置变量。下表列出了一些最常用的 CMake 变量:

变量 含义
CMAKE_PREFIX_PATH 搜索路径 dependent packages
CMAKE_MODULE_PATH 搜索其他 CMake 模块的路径
CMAKE_BUILD_TYPE 构建配置,例如 DebugRelease,确定调试/优化标志。这仅与单配置构建系统相关,例如MakefileNinja。用于 Visual Studio 和 Xcode 的多配置构建系统会忽略此设置。
CMAKE_INSTALL_PREFIX 将软件安装到构建 install目标的位置
CMAKE_TOOLCHAIN_FILE 包含交叉编译数据的文件,例如 toolchains and sysroots.
BUILD_SHARED_LIBS 是否构建共享库而不是静态库add_library() 没有类型的命令
CMAKE_EXPORT_COMPILE_COMMANDS 生成compile_commands.json 用于基于 clang 的工具的文件

其他特定于项目的变量可能可用于控制构建,例如启用或禁用项目的组件。

CMake 没有提供关于如何在不同提供的构建系统之间命名此类变量的约定,除了带有前缀的变量CMAKE_通常指的是 CMake 本身提供的选项,不应在第三方选项中使用,第三方选项应使用自己的前缀

构建系统

从命令行构建构建系统或项目,可以在构建目录中调用以下命令:

$ cmake --build .

--build标志启用特定的操作模式调用 CMAKE_MAKE_PROGRAM 关联的 generator,或用户配置的构建工具。

--build模式还接受参数--target以指定要构建的特定目标,例如特定库、可执行文件或自定义目标,或特定的特殊目标,如install

cmake --build . --target myexe

在多配置生成器的情况下,该--build模式还接受一个 参数来指定要构建的特定配置:--config

$ cmake --build . --target myexe --config Release

如果生成器生成特定于在使用调用 cmake 时选择的配置的构建系统,则该CMAKE_BUILD_TYPE 指定--config选项无效。

一些构建系统省略了构建期间调用的命令行的详细信息。该--verbose 标志可用于显示这些命令行:

$ cmake --build . --target myexe --verbose

构建目标

CMake 为所有提供 CMake 文件的构建系统提供了一些内置目标。

allMakefile和生成器使用的默认目标Ninja 。构建构建系统中的所有目标,除了那些被它们排除的目标 EXCLUDE_FROM_ALL目标或 EXCLUDE_FROM_ALL目录属性。该名称ALL_BUILD用于 Xcode 和 Visual Studio 生成器。help列出可用于构建的目标。该目标在使用时可用Unix Makefiles或者 Ninja生成器,确切的输出是特定于工具的。

clean删除构建的目标文件和其他输出文件。基于生成 Makefile器为每个目录创建一个clean目标,以便可以清理单个目录。该Ninja工具提供了自己的细粒度 系统。

-t cleantest运行测试。此目标仅在 CMake 文件提供基于 CTest 的测试时自动可用。另请参阅 运行测试

install安装软件。此目标仅在软件定义安装规则时自动可用 install()命令。另请参阅 软件安装

package创建一个二进制包。只有当 CMake 文件提供基于 CPack 的包时,此目标才会自动可用。

package_source创建源包。只有当 CMake 文件提供基于 CPack 的包时,此目标才会自动可用。

对于Makefile基于系统,/fast提供了二进制构建目标的变体。变/fast体用于构建指定的目标而不考虑其依赖性。不检查依赖项,如果过期则不重建。这Ninja 生成器在依赖性检查方面足够快,不会为该生成器提供此类目标。

--build 模式调用的程序由CMAKE_MAKE_PROGRAM指定的。对于大多数生成器,不需要配置特定程序。

CMAKE_INSTALL_PREFIX可以在 CMake 缓存中设置变量以指定安装提供的软件的位置。

运行测试

ctest(1)该工具随 CMake 发行版一起提供,用于执行提供的测试和报告结果。提供构建目标test以运行所有可用的测试,但是ctest(1)工具允许精细控制运行哪些测试、如何运行它们以及如何报告结果。

执行中 ctest(1)在构建目录中相当于运行test目标:

$ ctest

可以传递正则表达式以仅运行与表达式匹配的测试。仅运行以其 Qt名称命名的测试:

$ ctest -R Qt

正则表达式也可以排除测试。只运行没有Qt名字的测试:

$ ctest -E Qt

-j 测试可以通过将参数传递给并行运行ctest(1):

$ ctest -R Qt -j8

环境变量CTEST_PARALLEL_LEVEL 也可以设置为避免需要通过 -j.

默认情况下ctest(1)不打印测试的输出。命令行参数-V (或--verbose)启用详细模式以打印所有测试的输出。该--output-on-failure 选项仅打印失败测试的测试输出。环境变量CTEST_OUTPUT_ON_FAILURE 可以设置为作为将 选项传递给1的替代方法 --output-on-failurectest(1).

一个基本的出发点 (Step1)

最简单的项目是从源代码文件中构建一个可执行文件,CMakeLists.txt 文件仅需要两行,这将作为我们教程的起点,内容如下:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial tutorial.cxx)

文件中的命令支持大写、小写或者混合使用,这个例子中的命令使用小写。tutorial.cxx 用于计算一个数的平方根,源码的第一版非常简单:

// 计算一个数的平方根
#include <stdio.h>
#include <stdlib.h>
#include <math.h>int main (int argc, char *argv[])
{
  if (argc < 2)
    {
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}
添加一个版本号并配置头文件

你可以直接在源代码中添加版本号,但在 CMakeLists.txt 文件中提供版本号将会更加灵活,我们将文件修改如下:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
# 版本号 1.0
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)

# 配置一个头文件将一些 CMake 设置传入到源代码中
# 以 TutorialConfig.h.in 为模版,替换相关变量
# 以生成 TutorialConfig.h
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  )

# 将构建目录添加到 include 的搜索路径中以便找到
# TutorialConfig.h 文件
include_directories("${PROJECT_BINARY_DIR}")

# 添加可执行文件
add_executable(Tutorial tutorial.cxx)

因为配置文件将会写入到构建目录中,所以我们将这个目录添加到包含文件的搜索路径中。在源代码中添加 TutorialConfig.h.in 文件:

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

当 CMake 生成这个头文件时,@Tutorial_VERSION_MAJOR@ 和 @Tutorial_VERSION_MINOR@ 的值将会由 CMakeLists.txt 中对应的值替换。接下来我们将头文件包含到 tutorial.cxx 中并且使用这个版本号,代码如下:

// A simple program that computes the square root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"int main (int argc, char *argv[])
{
  if (argc < 2)
    {
    fprintf(stdout,"%s Version %d.%d\n",
            argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

主要的改变是包含了头文件并且在使用方法信息中打印了版本号。

添加一个库 (Step 2)

现在我们要在项目中添加一个库,这个库将会包含我们自己的计算平方根的实现。可执行文件将可以使用这个库,而不是使用编译器提供的平方根标准方法。本教程中将这个库放到名为 MathFunctions 的子文件夹中,这个子文件夹需要包含一个 CMakeLists.txt 文件,文件中有如下一行:

add_library(MathFunctions mysqrt.cxx)

mysqrt.cxx 文件中有一个叫做 mysqrt 的函数,它提供与编译器的 sqrt 函数相同的功能。我们在顶层的 CMakeLists.txt 中添加一个 add_subdirectory 调用以构建这个库。为了找到 MathFunctions/MathFunctions.h 头文件中的函数原型,我们添加另一条包含路径。最后一个改动是将这个库添加到可执行文件中。顶层 CMakeLists.txt 文件中添加的最新几行如下:

include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
add_subdirectory (MathFunctions)

# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)

考虑一下将这个库设计为可选的,本教程中这样做也许是不必要的,但是当使用更大的库或者第三方的库时你也许会用到。第一步是在顶层的 CMakeLists.txt 中添加一个选择:

# 是否使用我们自己的函数?
option (USE_MYMATH
        "Use tutorial provided math implementation" ON)

CMake GUI 中将会显示一个 ON 的默认值,用户可以按需更改。这个设置将会被缓存,这样在每次对这个项目运行 CMake 时用户不需要再次设置。接下来的更改是将 MathFunctions 库的构建和连接设置为可选的,我们在顶层 CMakeLists.txt 的最后修改如下:

# add the MathFunctions library?
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)

# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})

这将根据 USE_MYMATH 的设置来决定是否编译并使用 MathFunctions 库。注意这里使用了一个 EXTRA_LIBS 变量来收集任何可选的库,以在之后链接到可执行文件中。对有许多可选组件的项目,这是一种保持其整洁的常用方法。相应的源代码更改如下:

// A simple program that computes the square root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"
#ifdef USE_MYMATH
#include "MathFunctions.h"
#endif

int main (int argc, char *argv[])
{
  if (argc < 2)
    {
    fprintf(stdout,"%s Version %d.%d\n", argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }

  double inputValue = atof(argv[1]);

#ifdef USE_MYMATH
  double outputValue = mysqrt(inputValue);
#else
  double outputValue = sqrt(inputValue);
#endif

  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

在源代码中我们同样使用了 USE_MYMATH 变量。通过在 TutorialConfig.h.in 中添加如下配置,Cmake 将这个变量引入到源代码中:

#cmakedefine USE_MYMATH

安装与测试 (Step 3)

接下来我们在项目中添加安装规则和测试支持。安装规则非常直接,对于 MathFunctions 库的安装,我们在 MathFunctions 的 CMakeLists.txt 中添加如下几行:

install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

对于应用程序可执行文件和头文件的安装,我们在顶层的 CMakeLists.txt 中添加如下几行:

# add the install targets
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
         DESTINATION include)

万事俱备,接下来你应该可以构建这个项目,然后键入 make install (或者在 IDE 中构建 INSTALL 目标),它将会安装合适的头文件,库和执行文件。CMake 的 CMAKE_INSTALL_PREFIX 变量用于决定文件安装位置的根。添加测试也是一个同样直接的过程。在顶层 CMakeLists.txt 的结尾,我们可以添加几个基础测试以判别程序是否工作正常:

include(CTest)

# does the application run
add_test (TutorialRuns Tutorial 25)

# does it sqrt of 25
add_test (TutorialComp25 Tutorial 25)
set_tests_properties (TutorialComp25 PROPERTIES PASS_REGULAR_EXPRESSION "25 is 5")

# does it handle negative numbers
add_test (TutorialNegative Tutorial -25)
set_tests_properties (TutorialNegative PROPERTIES PASS_REGULAR_EXPRESSION "-25 is 0")

# does it handle small numbers
add_test (TutorialSmall Tutorial 0.0001)
set_tests_properties (TutorialSmall PROPERTIES PASS_REGULAR_EXPRESSION "0.0001 is 0.01")

# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number")

构建完成后,可以使用命令行工具 ctest 运行测试。第一个测试只是验证程序是否运行,没有段错误或其他的崩溃,并返回零值。这是一个 CTest 测试的基本形式。接下来的几个测试都使用 PASS_REGULAR_EXPRESSION 测试属性来验证测试的输出是否包含某些字符串。这样用来验证预期的计算结果,并且当参数数目不正确时打印使用信息。如果你想添加大量测试来测试不同的输入值,你可能会考虑创建如下所示的宏:

#define a macro to simplify adding tests, then use it
macro (do_test arg result)
  add_test (TutorialComp${arg} Tutorial ${arg})
  set_tests_properties (TutorialComp${arg}
    PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)

# do a bunch of result based tests
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")

每调用一次 do_test,根据传递的参数,都会添加一个拥有名字、输入和输出的测试。

添加系统自检 (Step 4)

接下来让我们向项目中添加一些代码,这些代码依赖的功能目标平台可能没有提供。这个例子中,我们添加的代码依赖于目标平台是否提供了对数 log 和指数 exp 函数。当然几乎所有的平台都提供了这样的函数,本教程假定它们是不常见的功能。如果平台提供了 log,那么我们可以在 mysqrt 函数中使用它计算平方根。我们首先使用顶层 CMakeLists.txt 文件中的 CheckFunctionExists.cmake 宏来测试这些功能的可用性,如下所示:

# does this system provide the log and exp functions?
include (CheckFunctionExists)
check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)

当 CMake 在平台上发现它们时,我们在 TutorialConfig.h.in 中定义这些值:

// does the platform provide exp and log functions?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

log 和 exp 的测试需要放在 configure_file 命令之前,configure_file 命令会立即使用 CMake 中的当前设置生成文件。当系统提供了这两个函数时,我们可以使用以下代码在 mysqrt 函数中提供一个基于 log 和 exp 的替代实现:

// if we have both log and exp then use them
#if defined (HAVE_LOG) && defined (HAVE_EXP)
  result = exp(log(x)*0.5);
#else // otherwise use an iterative approach
  . . .

添加生成文件和生成器 (Step 5)

在本节中,我们将展示如何将生成的源文件添加到应用程序的构建过程中。本例中,我们将会在构建过程中创建一个预先计算的平方根表,然后将这张表编译进我们的程序中。我们首先需要一个生成这张表的程序,为此我们在 MathFunctions 的子文件夹中添加一个新的名为 MakeTable.cxx 的源文件:

// A simple program that builds a sqrt table
#include <stdio.h>
#include <stdlib.h>
#include <math.h>int main (int argc, char *argv[])
{
  int i;
  double result;

  // make sure we have enough arguments
  if (argc < 2)
    {
    return 1;
    }

  // open the output file
  FILE *fout = fopen(argv[1],"w");
  if (!fout)
    {
    return 1;
    }

  // create a source file with a table of square roots
  fprintf(fout,"double sqrtTable[] = {\n");
  for (i = 0; i < 10; ++i)
    {
    result = sqrt(static_cast<double>(i));
    fprintf(fout,"%g,\n",result);
    }

  // close the table with a zero
  fprintf(fout,"0};\n");
  fclose(fout);
  return 0;
}

注意这张表会以有效的 C++ 代码的形式生成,输出文件的名字以参数的形式提供。接下来向 MathFunctions 的 CMakeLists.txt 文件中添加合适的命令以构建 MakeTable 的可执行文件,并运行它作为构建过程的一部分。需要几个命令来完成此操作,如下所示:

# first we add the executable that generates the table
add_executable(MakeTable MakeTable.cxx)

# add the command to generate the source code
add_custom_command (
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  )

# add the binary tree directory to the search path for
# include files
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )

# add the main library
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h  )

首先像添加其他执行文件那样添加 MakeTable 的执行文件。然后我们添加一个自定义命令以使用 MakeTable 生成 Table.h 文件。接下来我们需要将生成的文件添加到 MathFunctions 库的源文件列表中,以让 CMake 知道 mysqrt.cxx 依赖于 Table.h 文件。我们也需要将当前的构建文件夹添加到包含文件列表中,以让 Table.h 文件可以被发现并包含到 mysqrt.cxx 中。当构建这个项目时,它会先构建 MakeTable 的执行文件,然后运行 MakeTable 生成 Table.h 文件,最后它会编译包含有 Table.h 的 mysqrt.cxx 以生成 MathFunctions 库。此时,顶层 CMakeLists.txt 文件如下所示:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
include(CTest)

# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)

# does this system provide the log and exp functions?
include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)

check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)

# should we use our own math functions
option(USE_MYMATH
  "Use tutorial provided math implementation" ON)

# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  )

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories ("${PROJECT_BINARY_DIR}")

# add the MathFunctions library?
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)

# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})

# add the install targets
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
         DESTINATION include)

# does the application run
add_test (TutorialRuns Tutorial 25)

# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage
  PROPERTIES
  PASS_REGULAR_EXPRESSION "Usage:.*number"
  )


#define a macro to simplify adding tests
macro (do_test arg result)
  add_test (TutorialComp${arg} Tutorial ${arg})
  set_tests_properties (TutorialComp${arg}
    PROPERTIES PASS_REGULAR_EXPRESSION ${result}
    )
endmacro (do_test)

# do a bunch of result based tests
do_test (4 "4 is 2")
do_test (9 "9 is 3")
do_test (5 "5 is 2.236")
do_test (7 "7 is 2.645")
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")
do_test (0.0001 "0.0001 is 0.01")

TutorialConfig.h.in 如下:

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#cmakedefine USE_MYMATH

// does the platform provide exp and log functions?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

MathFunctions 的 CMakeLists.txt 文件如下:

# first we add the executable that generates the table
add_executable(MakeTable MakeTable.cxx)
# add the command to generate the source code
add_custom_command (
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  )
# add the binary tree directory to the search path
# for include files
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )

# add the main library
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h)

install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

构建安装程序 (Step 6)

接下来假设我们想将我们的项目分发给其他人,以便他们可以使用它。我们希望在各种平台上提供二进制和源代码分发。这与之前的第三步有些不同,在这个例子中,我们将构建安装包以支持二进制安装和包管理功能,比如 cygwin,debian,RPMs 等。我们将会使用 CPack 来创建平台相关的安装程序。具体来说,我们需要在我们的顶层 CMakeLists.txt 文件的底部添加几行:

# build a CPack driven installer package
include (InstallRequiredSystemLibraries)
set (CPACK_RESOURCE_FILE_LICENSE
     "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
include (CPack)

我们从包含 InstallRequiredSystemLibraries 开始。该模块包含有这个项目在当前平台所需的任何运行时库。然后我们设置一些 CPack 变量指明此项目许可证和版本信息的位置。版本信息使用了本教程前面设置的变量。最后我们包含了 CPack 模块,它将使用你设置的这些变量和其他系统属性来配置安装程序。

接下来就是按照通常的方法构建项目,然后运行 CPack 命令。要构建一个二进制分发,你可以运行:

cpack --config CPackConfig.cmake

要创建一个源码分发,你可以键入:

cpack --config CPackSourceConfig.cmake

添加对仪表板的支持 (Step 7)

添加将测试结果提交给仪表板的支持非常简单。在教程之前的步骤中已经定义了一些测试,我们只需运行这些测试并且将它们提交给一个仪表板。要包括对仪表板的支持,我们将 CTest 模块包含在我们的顶层 CMakeLists.txt 文件中:

# enable dashboard scripting
include (CTest)

我们还创建一个CTestConfig.cmake文件,可以在该文件中为仪表板指定此项目的名称。

set (CTEST_PROJECT_NAME "Tutorial")

当运行 CTest 时它会读取这个文件。要创建简单的仪表板,你可以在项目中运行 CMake,然后切换目录到构建目录中运行 ctest –D Experimental. 仪表板的结构将会上传到 Kitware 的公共仪表板中(这里)。