CMake教程

CMake教程

CMake是一个构建系统,可以用于构建跨平台的C和C++项目。其它的构建系统有makefile、MSBuild以及qmake。

使用CMake作为C或C++的构建系统已经变得越来越流行了,例如:

在使用一个第三方库时,例如Libevent。无论是在Linux还是Windows中,我们只需要进入它的源代码目录,然后在命令行中执行:

mkdir build
cd build
cmake ..
cmake --build .
cmake --install .

之后在我们自己的项目中,只需要在CMakeLists.txt中添加:

find_package(Libevent REQUIRED core)
target_link_libraries(你的可执行目标 libevent::core)

即可使用该库。

对于一部分人来说,了解上面这些就足够了。但如果想进一步地学习CMake构建系统,可以查看CMake官方文档CMake Wiki

下面是CMake官方文档中的一篇教程,你可以跟着这些步骤一步一步地操作,并学习CMake构建系统。同时,我们还能感受到C或C++为了跨平台而付出的努力。

引入

本教程是循序渐进的,它包括CMake能解决的常见的构建系统问题。在一个示例项目中查看不同的主题之间如何协同工作,对于理解CMake非常有帮助。该教程中所有案例的源代码可以在CMake源码下的Help/guide/tutorial目录中找到(GitHub链接)。每一步都有独立的子目录,其中包含了可能会用到的代码。教程示例是渐进式的,因此每个步骤都为上一步提供了完整的解决方案。

第1步 开始

最基础的项目是将源代码构建成可执行文件。对于一个简单的项目,只需要一个3行的CMakeLists.txt文件即可。在Step1目录下创建一个CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.10)

# 设置项目名
project(Tutorial)

# 添加可执行目标
add_executable(Tutorial tutorial.cxx)

注意:CMake支持大写、小写或大小写混合命令。但在这些例子中,每个CMakeLists.txt文件都使用小写命令。tutorial.cxx中的源代码放在Step1目录下,它用于计算一个数的平方根。

添加版本号并且配置头文件

我们将添加的第一个特性是:为我们的可执行文件和项目提供一个版本号。尽管我们可以在源代码中做到这一点,但是使用CMakeLists.txt会更加灵活。

首先,修改CMakeLists.txt文件,使用project()命令设置项目名和版本号:

cmake_minimum_required(VERSION 3.10)

# 设置项目名和版本号
project(Tutorial VERSION 1.0)

然后,配置一个头文件并将版本号传递给源代码:

configure_file(TutorialConfig.h.in TutorialConfig.h)

因为配置的文件将被写到binary tree目录下(CMakeCache.txt所在的目录,即build目录),所以我们必须将那个目录添加到include搜索路径列表中。将下面这行添加到CMakeLists.txt文件的末尾:

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

使用你最喜欢的编辑器,在源代码目录(Step1目录)中创建TutorialConfig.h.in,其中包含以下内容:

// 该教程的配置选项和设置
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

当CMake配置此头文件时,@Tutorial_VERSION_MAJOR@@Tutorial_VERSION_MINOR@的值将被替换。

然后修改tutorial.cxx,让它包含头文件TutorialConfig.h

最后,更新tutorial.cxx,让它打印可执行文件名和版本号,如下所示:

  if (argc < 2) {
    // 打印版本号
    std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
              << Tutorial_VERSION_MINOR << std::endl;
    std::cout << "Usage: " << argv[0] << " number" << std::endl;
    return 1;
  }

指定C++标准

接下来,给我们的项目添加一些C++11特性,在tutorial.cxx中用std::stod替换atof。同时,删除#include<cstdlib>

const double inputValue = std::stod(argv[1]);

在CMake中指定C++标准最简单的方法是使用CMAKE_CXX_STANDARD变量。将CMakeLists.txt文件中的CMAKE_CXX_STANDARD变量设置为11,并将CMAKE_CXX_STANDARD_REQUIRED设置为True。确保将CMAKE_CXX_STANDARD声明添加到add_executable的上面:

cmake_minimum_required(VERSION 3.10)

# 设置项目名和版本号
project(Tutorial VERSION 1.0)

# 指定c++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

构建和测试

运行 cmakecmake-gui 来配置(configure)项目,然后使用你所选的构建工具构建(build)它。

例如,在命令行中,我们应该导航到CMake源码中的Help/guide/tutorial目录中,然后创建构建目录:

mkdir Step1_build

接下来,导航到构建目录并运行CMake,让CMake配置项目并生成一个本地构建系统:

cd Step1_build
cmake ../Step1

然后调用那个构建系统来编译、链接该项目:

cmake --build .

最后,尝试使用新生成可执行文件Tutorial,你可以运行以下命令:

Tutorial 4294967296
Tutorial 10
Tutorial

第2步 添加一个库

现在,我们将添加一个库到项目中。这个库包含了我们自己实现的计算平方根的算法。之后的可执行文件可以使用这个库而不是编译器提供的标准平方根函数。

我们把这个库放进一个名为MathFunctions的子目录中,这个目录已经包含了一个头文件MathFunctions.h和一个源文件mysqrt.cxx。这个源文件有一个名为mysqrt的函数,它提供了和标准库中的sqrt相似的功能。

MathFunctions目录中创建CMakeLists.txt文件,并将下面这行添加到MathFunctions目录中的CMakeLists.txt文件中:

add_library(MathFunctions mysqrt.cxx)

要利用这个库,我们需要在顶级目录(Step2目录)下的CMakeLists.txt文件中添加一个add_subdirectory()调用,以便该库可以被构建。我们在可执行目标中添加这个新的库,然后添加MathFunctions目录作为include目录以便头文件mqsqrt.h能够被找到。根目录(Step2目录)下CMakeLists.txt文件的最后几行现在应该如下所示:

# 添加MathFunctions库
add_subdirectory(MathFunctions)

# 添加可执行目标
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC MathFunctions)

# 添加binary tree目录到include文件的搜索路径
# 以便我们能找到TutorialConfig.h
target_include_directories(Tutorial PUBLIC
                          "${PROJECT_BINARY_DIR}"
                          "${PROJECT_SOURCE_DIR}/MathFunctions"
                          )

现在,让我们将MathFunctions库设置为可选。虽然对于该教程来说确实不需要这样做,但是对于更大的项目来说,这是常见的事情。第一步是向顶级目录下的CMakeLists.txt文件添加一个选项。

option(USE_MYMATH "Use tutorial provided math implementation" ON)

# 配置一个头文件,传递一些CMake设置到源代码
configure_file(TutorialConfig.h.in TutorialConfig.h)

这个选项将显示在 cmake-guiccmake 中,使用默认值ON,用户可以更改该值。这个设置将存储在缓存中,以便用户不需要每次在构建目录上运行CMake时都设置该值。

下一个更改是使构建和链接MathFunctions库成为一个条件。为此,我们将根目录下CMakeLists.txt文件的结尾更改为:

if(USE_MYMATH)
  add_subdirectory(MathFunctions)
  list(APPEND EXTRA_LIBS MathFunctions)
  list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()

# 添加可执行目标
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})

# 添加binary tree目录到include文件的搜索路径
# 以便我们能找到TutorialConfig.h
target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           ${EXTRA_INCLUDES}
                           )

注意:使用变量EXTRA_LIBS收集所有可选库,以便之后链接到可执行文件中。类似地,变量EXTRA_INCLUDES表示可选的头文件。这是处理多个可选组件的一种传统方式,下一步我们将介绍现代方式。

对源代码的更改非常简单。首先,在tutorial.cxx中,包含头文件MathFunctions.h,如果我们需要的话:

#ifdef USE_MYMATH
#  include "MathFunctions.h"
#endif

然后,在同一个文件中,通过USE_MYMATH控制要使用哪个平方根函数:

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

因为源代码现在需要USE_MYMATH,所以我们将下面这行添加到

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值