CMake教程(一)

CMake 是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile 或者 project 文件,能测试编译器所支持的 C++ 特性,类似 UNIX 下的 automake 。只是 CMake 的组态档取名为 CMakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是 CMake 和 SCons 等其他类似系统的区别之处。

首先从CMake下载页面下载最新的源码包,解压缩之后可以查看所有的源码,包括我们下面需要用到的CMake 教程。

CMake 教程提供了逐步指南,涵盖了 CMake 可以解决的常见构建系统问题。了解示例项目中各个主题如何协同工作将非常有帮助。教程文档和示例的源代码可以在 CMake 源代码树的Help/guide/tutorial目录中找到 。每个步骤都有其自己的子目录,其中包含可以用作起点的代码。教程示例是渐进式的,因此每个步骤都为上一步提供了完整的解决方案,如下所示:
CMake教程(一)_第1张图片

一个基本的出发点 (Step1)

最基本的项目是从源代码文件构建的可执行文件。对于简单的项目,只需三行CMakeLists.txt文件。这将是本教程的起点。CMakeLists.txtStep1目录中创建一个 文件,如下所示:

cmake_minimum_required(VERSION 3.10)

# set the project name
project(Tutorial)

# add the executable
add_executable(Tutorial tutorial.cxx)

请注意,此示例在CMakeLists.txt文件中使用小写命令。CMake 支持大写,小写和大小写混合命令。Step1目录中tutorial.cxx提供的源代码,可用于计算数字的平方根。

添加一个版本号并配置头文件

我们将添加的第一个功能是为我们的可执行文件和项目提供版本号。虽然我们可以在源代码中专门执行此操作,但使用 CMakeLists.txt可以提供更大的灵活性。

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

cmake_minimum_required(VERSION 3.10)

# set the project name and version
project(Tutorial VERSION 1.0)

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

configure_file(TutorialConfig.h.in TutorialConfig.h)

由于已配置的文件将被写入二进制树,因此我们必须将该目录添加到路径列表中以搜索包含文件。将以下行添加到CMakeLists.txt文件的末尾:

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

因为配置文件将会写入到构建目录中,所以我们将这个目录添加到包含文件的搜索路径中。在源代码中添加 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 中并且使用这个版本号,代码如下:

  if (argc < 2) {
    // report version
    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 功能。

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

我们将需要在 CMake 代码中明确声明应使用正确的标志。在 CMake 中启用对特定 C++ 标准的支持的最简单方法是使用CMAKE_CXX_STANDARD变量。对于本教程,请设置CMAKE_CXX_STANDARDCMakeLists.txt文件中的变量设置为11并把CMAKE_CXX_STANDARD_REQUIRED 改为True:

cmake_minimum_required(VERSION 3.10)

# set the project name and version
project(Tutorial VERSION 1.0)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

构建和测试

运行 cmake 可执行文件或 cmake-gui 配置项目,然后使用您选择的构建工具进行构建。

例如,从命令行我们可以导航到Help/guide/tutorialCMake源代码树的目录并运行以下命令:

mkdir Step1_build
cd Step1_build
cmake ../Step1
cmake --build .

导航到构建 Tutorial 的目录(可能是make目录或Debug或Release构建配置子目录),然后运行以下命令:

Tutorial 4294967296
Tutorial 10
Tutorial

添加一个库 (Step 2)

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

在本教程中,我们将库放入名为的子目录中 MathFunctions 。该目录已经包含一个头文件 MathFunctions.h 和一个源文件mysqrt.cxx。源文件具有一个mysqrt功能,该功能提供与编译器sqrt功能相似的功能。

本教程中将这个库放到名为 MathFunctions 的子文件夹中,这个子文件夹需要包含一个 CMakeLists.txt 文件,文件中有如下一行:

add_library(MathFunctions mysqrt.cxx)

为了利用新库,我们将添加一个 add_subdirectory() 调用顶级 CMakeLists.txt 文件,以便构建库。我们将新库添加到可执行文件,并添加 MathFunctions 为包含目录,以便可以找到头文件 mqsqrt.h。现在,顶级 CMakeLists.txt 文件的最后几行应如下所示:

# add the MathFunctions library
add_subdirectory(MathFunctions)

# add the executable
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC MathFunctions)

# add the binary tree to the search path for include files
# so that we will find 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)

# configure a header file to pass some of the CMake settings
# to the source code
configure_file(TutorialConfig.h.in TutorialConfig.h)

此选项将显示在 cmake-gui 和 ccmake 用户可以更改的默认值 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 the executable
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})

# add the binary tree to the search path for include files
# so that we will find 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 变量。通过在 TutorialConfig.h.in 中添加如下配置,Cmake 将这个变量引入到源代码中:

#cmakedefine USE_MYMATH

添加库的使用要求(Step 3)

使用要求可以更好地控制库或可执行文件的链接并包含行,同时还可以更好地控制 CMake 内部目标的传递属性。利用使用需求的主要命令是:

target_compile_definitions()
target_compile_options()
target_include_directories()
target_link_libraries()

让我们从添加库(Step 2)中重构代码,以使用现代 CMake 使用需求方法。我们首先声明,链接到 MathFunctions 的任何人都需要包括当前源目录,而 MathFunctions 本身不需要。因此这可能成为INTERFACE使用要求。

记住INTERFACE是指消费者需要的东西,而生产者则不需要。将以下行添加到 MathFunctions/CMakeLists.txt 的末尾 :

target_include_directories(MathFunctions
          INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
          )

现在我们已经为math_functions指定了使用要求,我们可以安全地从顶级 CMakeLists.txt 中删除EXTRA_INCLUDES变量的使用:

if(USE_MYMATH)
  add_subdirectory(MathFunctions)
  list(APPEND EXTRA_LIBS MathFunctions)
endif()

以及这里:

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

完成后,运行 cmake 可执行文件或 cmake-gui 配置项目,然后使用您选择的构建工具或通过cmake --build构建目录进行构建。 .

你可能感兴趣的:(C,&&,C++)