本文最后更新于:2024-11-18T14:20:10+08:00
文章来源:https://github.com/chaneyzorn/CMake-tutorial/blob/master/README.md
CMake-tutorial(原文)
这份渐进式的教程涵盖了 CMake 帮助处理的一些常见的构建问题。许多议题已经在《Mastering CMake》中作为独立的话题介绍过,但是了解它们是如何在示例项目中结合在一起的将非常有帮助。你可以在 CMake 源码中的 Tests/Tutorial 文件夹找到这份教程,每一步的内容都放置在各自的子文件夹中。
一个基本的出发点 (Step1)
最简单的项目是从源代码文件中构建一个可执行文件,CMakeLists.txt 文件仅需要两行,这将作为我们教程的起点,内容如下:
文件中的命令支持大写、小写或者混合使用,这个例子中的命令使用小写。tutorial.cxx 用于计算一个数的平方根,源码的第一版非常简单:
添加一个版本号并配置头文件
你可以直接在源代码中添加版本号,但在 CMakeLists.txt 文件中提供版本号将会更加灵活,我们将文件修改如下:
因为配置文件将会写入到构建目录中,所以我们将这个目录添加到包含文件的搜索路径中。在源代码中添加 TutorialConfig.h.in 文件:
当 CMake 生成这个头文件时,@Tutorial_VERSION_MAJOR@ 和 @Tutorial_VERSION_MINOR@ 的值将会由 CMakeLists.txt 中对应的值替换。接下来我们将头文件包含到 tutorial.cxx 中并且使用这个版本号,代码如下:
主要的改变是包含了头文件并且在使用方法信息中打印了版本号。
添加一个库 (Step 2)
现在我们要在项目中添加一个库,这个库将会包含我们自己的计算平方根的实现。可执行文件将可以使用这个库,而不是使用编译器提供的平方根标准方法。本教程中将这个库放到名为 MathFunctions 的子文件夹中,这个子文件夹需要包含一个 CMakeLists.txt 文件,文件中有如下一行:
mysqrt.cxx 文件中有一个叫做 mysqrt 的函数,它提供与编译器的 sqrt 函数相同的功能。我们在顶层的 CMakeLists.txt 中添加一个 add_subdirectory 调用以构建这个库。为了找到 MathFunctions/MathFunctions.h 头文件中的函数原型,我们添加另一条包含路径。最后一个改动是将这个库添加到可执行文件中。顶层 CMakeLists.txt 文件中添加的最新几行如下:
考虑一下将这个库设计为可选的,本教程中这样做也许是不必要的,但是当使用更大的库或者第三方的库时你也许会用到。第一步是在顶层的 CMakeLists.txt 中添加一个选择:
CMake GUI 中将会显示一个 ON 的默认值,用户可以按需更改。这个设置将会被缓存,这样在每次对这个项目运行 CMake 时用户不需要再次设置。接下来的更改是将 MathFunctions 库的构建和连接设置为可选的,我们在顶层 CMakeLists.txt 的最后修改如下:
这将根据 USE_MYMATH 的设置来决定是否编译并使用 MathFunctions 库。注意这里使用了一个 EXTRA_LIBS 变量来收集任何可选的库,以在之后链接到可执行文件中。对有许多可选组件的项目,这是一种保持其整洁的常用方法。相应的源代码更改如下:
在源代码中我们同样使用了 USE_MYMATH 变量。通过在 TutorialConfig.h.in 中添加如下配置,Cmake 将这个变量引入到源代码中:
安装与测试 (Step 3)
接下来我们在项目中添加安装规则和测试支持。安装规则非常直接,对于 MathFunctions 库的安装,我们在 MathFunctions 的 CMakeLists.txt 中添加如下几行:
对于应用程序可执行文件和头文件的安装,我们在顶层的 CMakeLists.txt 中添加如下几行:
万事俱备,接下来你应该可以构建这个项目,然后键入 make install
(或者在 IDE 中构建 INSTALL 目标),它将会安装合适的头文件,库和执行文件。CMake 的 CMAKE_INSTALL_PREFIX 变量用于决定文件安装位置的根。添加测试也是一个同样直接的过程。在顶层 CMakeLists.txt 的结尾,我们可以添加几个基础测试以判别程序是否工作正常:
构建完成后,可以使用命令行工具 ctest
运行测试。第一个测试只是验证程序是否运行,没有段错误或其他的崩溃,并返回零值。这是一个 CTest 测试的基本形式。接下来的几个测试都使用 PASS_REGULAR_EXPRESSION 测试属性来验证测试的输出是否包含某些字符串。这样用来验证预期的计算结果,并且当参数数目不正确时打印使用信息。如果你想添加大量测试来测试不同的输入值,你可能会考虑创建如下所示的宏:
每调用一次 do_test,根据传递的参数,都会添加一个拥有名字、输入和输出的测试。
添加系统自检 (Step 4)
接下来让我们向项目中添加一些代码,这些代码依赖的功能目标平台可能没有提供。这个例子中,我们添加的代码依赖于目标平台是否提供了对数 log 和指数 exp 函数。当然几乎所有的平台都提供了这样的函数,本教程假定它们是不常见的功能。如果平台提供了 log,那么我们可以在 mysqrt 函数中使用它计算平方根。我们首先使用顶层 CMakeLists.txt 文件中的 CheckFunctionExists.cmake 宏来测试这些功能的可用性,如下所示:
当 CMake 在平台上发现它们时,我们在 TutorialConfig.h.in 中定义这些值:
log 和 exp 的测试需要放在 configure_file 命令之前,configure_file 命令会立即使用 CMake 中的当前设置生成文件。当系统提供了这两个函数时,我们可以使用以下代码在 mysqrt 函数中提供一个基于 log 和 exp 的替代实现:
添加生成文件和生成器 (Step 5)
在本节中,我们将展示如何将生成的源文件添加到应用程序的构建过程中。本例中,我们将会在构建过程中创建一个预先计算的平方根表,然后将这张表编译进我们的程序中。我们首先需要一个生成这张表的程序,为此我们在 MathFunctions 的子文件夹中添加一个新的名为 MakeTable.cxx 的源文件:
注意这张表会以有效的 C++ 代码的形式生成,输出文件的名字以参数的形式提供。接下来向 MathFunctions 的 CMakeLists.txt 文件中添加合适的命令以构建 MakeTable 的可执行文件,并运行它作为构建过程的一部分。需要几个命令来完成此操作,如下所示:
首先像添加其他执行文件那样添加 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 文件如下所示:
TutorialConfig.h.in 如下:
MathFunctions 的 CMakeLists.txt 文件如下:
构建安装程序 (Step 6)
接下来假设我们想将我们的项目分发给其他人,以便他们可以使用它。我们希望在各种平台上提供二进制和源代码分发。这与之前的第三步有些不同,在这个例子中,我们将构建安装包以支持二进制安装和包管理功能,比如 cygwin,debian,RPMs 等。我们将会使用 CPack 来创建平台相关的安装程序。具体来说,我们需要在我们的顶层 CMakeLists.txt 文件的底部添加几行:
我们从包含 InstallRequiredSystemLibraries 开始。该模块包含有这个项目在当前平台所需的任何运行时库。然后我们设置一些 CPack 变量指明此项目许可证和版本信息的位置。版本信息使用了本教程前面设置的变量。最后我们包含了 CPack 模块,它将使用你设置的这些变量和其他系统属性来配置安装程序。
接下来就是按照通常的方法构建项目,然后运行 CPack 命令。要构建一个二进制分发,你可以运行:
要创建一个源码分发,你可以键入:
添加对仪表板的支持 (Step 7)
添加将测试结果提交给仪表板的支持非常简单。在教程之前的步骤中已经定义了一些测试,我们只需运行这些测试并且将它们提交给一个仪表板。要包括对仪表板的支持,我们将 CTest 模块包含在我们的顶层 CMakeLists.txt 文件中:
我们还创建一个CTestConfig.cmake文件,可以在该文件中为仪表板指定此项目的名称。
当运行 CTest 时它会读取这个文件。要创建简单的仪表板,你可以在项目中运行 CMake,然后切换目录到构建目录中运行 ctest –D Experimental
. 仪表板的结构将会上传到 Kitware 的公共仪表板中(这里)。