练习1 -建立一个基本项目
教程所使用的实例代码见本文资源绑定的文件。
最基本的CMake项目是从单个源代码文件构建的可执行文件。对于这样的简单项目,只需要一个包含三个命令的CMakeLists.txt文件。
注意:虽然CMake支持大写,小写和混合大小写命令,但小写命令是首选,并将在整个教程中使用。
任何项目的最重要的CMakeLists.txt必须从使用cmake_minimum_required()命令指定最小CMake版本开始。这将建立策略设置,并确保以下CMake函数与CMake的兼容版本一起运行。
要启动一个项目,我们使用project()命令来设置项目名称。这个调用对于每个项目都是必需的,应该在cmake_minimum_required()之后调用,该命令还可以用于指定其他项目级别的信息,如语言或版本号。
最后,add_executable()命令告诉CMake使用指定的源代码文件创建一个可执行文件。
目标
了解如何创建一个简单的CMake项目。
如上所述,三行CMakeLists.txt是我们启动和运行所需的全部内容。第一行使用cmake_minimum_required()设置CMake版本,如下所示:
// TODO 1: CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
下一步创建基本项目,使用project()命令设置项目名称,如下所示:
// TODO 2: CMakeLists.txt
project(Tutorial)
为基本项目调用的最后一个命令是add_executable():
//TODO 3: CMakeLists.txt
add_executable(Tutorial tutorial.cxx)
练习2 -指定c++标准
CMake有一些特殊的变量,这些变量要么是在幕后创建的,要么是在项目代码中设置的。这些变量中有许多以CMAKE_开头。在为项目创建变量时避免这种命名约定。其中两个特殊的用户可设置变量是CMAKE_CXX_STANDARD和CMAKE_CXX_STANDARD_REQUIRED。它们可以一起用于指定构建项目所需的c++标准。
目标
添加一个需要c++ 11支持的特性。
步骤
继续编辑Step1目录中的文件。从TODO 4开始,完成TODO 6。
首先,通过添加一个需要c++ 11的特性。然后更新CMakeLists.txt以要求c++ 11。
操作
我们首先通过在tutorial.cxx中将atof替换为std::stod来为我们的项目添加一些c++ 11特性。它看起来像下面这样:
// TODO 4: tutorial.cxx
const double inputValue = std::stod(argv[1]);
要完成TODO 5,只需删除#include <cstdlib>。
我们需要在CMake代码中明确声明它应该使用正确的标志。在CMake中启用对特定c++标准的支持的一种方法是使用CMAKE_CXX_STANDARD变量。在本教程中,将CMakeLists.txt文件中的CMAKE_CXX_STANDARD变量设置为11,将CMAKE_CXX_STANDARD_REQUIRED设置为True。确保在add_executable()调用的上方添加CMAKE_CXX_STANDARD声明。
//TODO 6: CMakeLists.txt
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
练习3 -添加版本号和配置的头文件
有时,让CMakelists.txt文件中定义的变量在源代码中也可用可能是有用的。在这种情况下,我们希望打印项目版本。
实现这一目标的一种方法是使用配置好的头文件。我们创建一个输入文件,其中包含一个或多个要替换的变量。这些变量具有类似于@VAR@.的特殊语法,然后,我们使用configure_file()命令将输入文件复制到给定的输出文件中,并用CMakelists.txt文件中VAR的当前值替换这些变量。
目标
定义并传递项目的版本号。
步骤
继续从步骤1编辑文件。从TODO 7开始,完成TODO 12。在这个练习中,我们首先在CMakeLists.txt中添加一个项目版本号。在同一个文件中,使用configure_file()将给定的输入文件复制到输出文件中,并在输入文件内容中替换一些变量值。
接下来,在定义版本号时创建一个输入头文件tutorialconfig .h.,它将接受从configure_file()传递的变量。
最后,更新tutorial.cxx
,打印出它的版本号。
操作
在本练习中,我们通过打印版本号来改进可执行文件。虽然我们可以只在源代码中这样做,但使用CMakeLists.txt可以让我们维护版本号的单一数据源。
首先,我们修改CMakeLists.txt文件,使用project()命令设置项目名称和版本号。当project()命令被调用时,CMake在幕后定义Tutorial_VERSION_MAJOR和Tutorial_VERSION_MINOR。
// TODO 7: CMakeLists.txt
project(Tutorial VERSION 1.0)
然后我们使用configure_file()复制输入文件,替换指定的CMake变量:
// TODO 8: CMakeLists.txt
configure_file(TutorialConfig.h.in TutorialConfig.h)
configure_file(TutorialConfig.h.in TutorialConfig.h)
的作用是使用一个输入文件 TutorialConfig.h.in
,并根据当前的CMake配置和变量的设置,生成一个输出文件 TutorialConfig.h
。
这行代码的功能包括:
-
输入文件和输出文件:
TutorialConfig.h.in
是一个模板文件,通常包含了一些占位符或者变量,用来在生成阶段替换为实际的值。TutorialConfig.h
是生成的最终文件,它将会包含从模板文件中处理得到的最终内容。
-
配置文件处理:
- 在 CMake 的配置过程中,可以定义一些变量或者选项,用来决定生成的内容。比如,可以根据用户的选择来定义一些预处理宏或者其他的配置信息。
-
生成文件的位置:
- 生成的
TutorialConfig.h
文件会放置在 CMakeLists.txt 文件所在目录的相对位置。
- 生成的
-
变量替换:
- 如果
TutorialConfig.h.in
文件中包含了 CMake 的变量或者表达式,例如${VAR}
,在生成过程中,这些变量会被替换为实际的值。
- 如果
总结来说,这行代码的作用是根据指定的模板文件 TutorialConfig.h.in
,生成一个实际的配置文件 TutorialConfig.h
,并根据当前的 CMake 配置选项和变量值进行相应的处理和替换。
由于配置的文件将被写入项目二进制目录,我们必须将该目录添加到搜索包含文件的路径列表中。
使用target_include_directories()来指定可执行目标应该在哪里查找包含文件。
// TODO 9: CMakeLists.txt
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
TutorialConfig.h.in
是要配置的输入头文件。当configure_file()从CMakeLists.txt调用时,@Tutorial_VERSION_MAJOR@和@Tutorial_VERSION_MINOR@的值将被tutorial_config .h中项目的相应版本号所替换。
// TODO 10: TutorialConfig.h.in
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
接下来,我们需要修改tutorial.cxx
以包含已配置的头文件TutorialConfig.h。
// TODO 11: tutorial.cxx
#include "TutorialConfig.h"
最后,通过修改tutorial.cxx
文件来打印出可执行文件名和版本号,如下:
// TODO 12 : 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;
}
编译并运行
一旦完成了TODO 1到TODO 3,我们就可以编译和运行我们的项目了。
进入到CMake实例代码的cmake-3.30.0-tutorial-source目录下,并创建一个build目录:
mkdir Step1_build
接下来,进入到Step1_build目录并生成一个本地编译系统:
cd Step1_build
cmake ../Step1
然后调用编译系统来编译/链接项目:
cmake --build .
// 或者采用以下命令
sudo make
最后,运行如下命令进行简单测试:
./Tutorial 4294967296
./Tutorial 10
./Tutorial