
Intro
- 上一篇我们学习了三种描述项目结构的API
- 开讲之前呢,我们先来复习一下
// 指定CMake项目最低版本
cmake_minimum_required(VERSION 3.10)
// 为项目命名
project(ACM_1)
// 为项目添加可执行文件
add_executable(ACM_1 main.cxx)
Q? & A!
- Q: 这篇A菌要介绍些什么呢?
- 本篇围绕几个环境变量(内置变量常常以
CMAKE_开头)。 - 如何描述项目中存有的
.h头文件呢? - 如何设置变量并替换进代码 ?
- 本篇围绕几个环境变量(内置变量常常以
开始
Step1: 指定C++标准库版本
- 为什么要指定版本呢?
- A菌机器上安装的环境为C99,B菌为C11,C菌为....
- 环境不同但代码相同,一定会有问题。
- 那么A菌在使用C++11API的时候呢,在CMake文件中描述一下。
- 这样可以告知CMake我们使用的标准库版本,让CMake为我们正确的构建代码。
- 亦或是对代码结构进行约束的作用。
// main.cpp
// 这些都是标准库,标准库可以理解成 官方提供的API
#include <cmath> // 提供数学函数
#include <cstdlib> // 提供通用工具函数
#include <iostream> // 提供输入输出流功能。
#include <string> // 提供字符串处理功能
// main 函数是程序的入口点
// argc 是命令行参数的数量
// argv 是命令行参数的数组
int main(int argc, char* argv[])
{
// 检查命令行参数的数量。如果参数少于 2 个(即没有提供数字),则输出使用说明并返回 1,表示错误。
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
// 将命令行参数转换为 `double` 类型的数字。
// const double inputValue = atof(argv[1]);
const double inputValue = std::stod(argv[1]);
// 计算输入值的平方根,并输出结果。程序返回 0,表示成功。
const double outputValue = sqrt(inputValue);
std::cout << "The square root of " << inputValue << " is " << outputValue
<< std::endl;
return 0;
}
- 首先我们拿出上篇文章的计算平方根代码
- 其次我们使用stof替换
const double inputValue = atof(argv[1]);代码
# 在原基础的配置中加入如下配置
# CMAKE_CXX_STANDARD`用于指定项目所需的 C++ 标准版本。
# set(CMAKE_CXX_STANDARD 11)表示使用 C++11 标准。
# set 可以理解为为 CMake设置环境变量
set(CMAKE_CXX_STANDARD 11)
# CMAKE_CXX_STANDARD_REQUIRED用于指定所需的 C++ 标准是否是强制性的。
# 如果设置为 `True`,则编译器必须支持指定的 C++ 标准。
set(CMAKE_CXX_STANDARD_REQUIRED True)
- 这里我们用到了3个API,含义已经在注释中了
CMAKE_CXX_STANDARDCMAKE_CXX_STANDARD_REQUIREDset
- CMake中定义了很多环境变量例如(只列举一下,后续使用我们在详细解释)
CMAKE_BUILD_TYPE指定构建类型(如 Debug、Release)。CMAKE_INSTALL_PREFIX指定安装路径。CMAKE_SOURCE_DIR项目的根目录。CMAKE_BINARY_DIR构建目录。
# 尝试编译
cd build
cmake ..
make
Step2: 描述头文件,替换变量
- 这里我们先删除掉上面修改的代码,然后专心试用一些新的API
- 考虑一个需求,在我们使用
cli --version时

- 这里显示的
3.30.5版本我们除了硬编码的方式,还有其他别的什么实现方式吗? - CMake为我们提供了变量替换功能(其实叫做指定配置文件啦),这样我们就可以使用名为
configure_file的函式来让CMake构建程式时为我们替换其中的变量啦。

- 首先创建头文件,其次定义两个常量。
ACM_1部分为CMakeLists中的project指定的项目名称。_VERSION_MAJOR与_VERSION_MINOR是固定写法啦。

- 然后为
project函数添加两个参数VERSION和版本号。1为_VERSION_MAJOR0位_VERSION_MINOR

- 最后呢,我们使用
configure_file来描述一下项目的配置文件替换。 - 在
main代码中引用我们的Config.h头描述文件。
注意哦: 在创建替换文件时我们使用
.h.in这里引入的为.h。
- 加入代码输出一下试试看。
Step3: 构建项目
- 那这里A菌在演示最后一次规范流程哦。
- 后续构建项目打包时就以
打包构建代替这个过成了喔。
# 创建build目录
mkdir build
# 切换工作目录为build目录
cd build
# 使用CMake生成项目打包配置
cmake ..
# 打包编译
make
Step4: 出错了喔

- 编译器说: 我找不到代码中包含的
Config.h文件。
如何解决这个问题呢?
- 这里CMake又提供给我们一个名为
target_include_directories的API。 - 用于指定目标的包含目录,使编译器能够找到头文件。

- 添加
target_include_directories(ACM_1 PUBLIC "${PROJECT_BINARY_DIR}")配置,我们来帮编译器解除问题。 PROJECT_BINARY_DIR是什么呢?- 是CMake里自带的环境变量。
message是print的意思,我们打印出来,看看是什么内容呢。

- 再来。
- 这次打印出了
PROJECT_BINARY_DIR的路径,并且编译过程很顺利。 - 运行二进制程式,输出了版本号。
总结
CMAKE_CXX_STANDARDCMAKE_CXX_STANDARD_REQUIREDsetproject(NAME VERSION x.x.x)configure_file()target_include_directories()message
你能否回忆起以上内容都是什么含义和功用呢?如果有问题的话要好好回顾一下哦。实在不理解也可以留言喔。 下面附上代码
Code
- CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(ACM_1 VERSION 1.0)
add_executable(ACM_1 main.cxx)
configure_file(Config.h.in Config.h)
target_include_directories(ACM_1 PUBLIC "${PROJECT_BINARY_DIR}")
message("CMAKE_BINARY_DIR: ${PROJECT_BINARY_DIR}")
- Config.h.in
// the configured options and settings for Tutorial
#define ACM_1_VERSION_MAJOR @ACM_1_VERSION_MAJOR@
#define ACM_1_VERSION_MINOR @ACM_1_VERSION_MINOR@
- main.cxx
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>
#include "Config.h"
int main(int argc, char *argv[])
{
if (argc < 2)
{
// report version
std::cout << argv[0] << " Version " << ACM_1_VERSION_MAJOR << "."
<< ACM_1_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
const double inputValue = atof(argv[1]);
const double outputValue = sqrt(inputValue);
std::cout << "The square root of " << inputValue << " is " << outputValue
<< std::endl;
return 0;
}