对比官方文档练习
step1 基本起始点
一个基本的项目:从源文件构建可执行程序
文件目录如下
编写 CMakeLists.txt 如下:
# cmake 要求的最小版本
cmake_minimum_required(VERSION 3.24)
# 设置项目名称 可以设置版本号
project(Tutorial VERSION 1.0)
# 设置 c++ 的语言标准 C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(TutorialConfig.h.in TutorialConfig.h)
# 添加可执行程序(前面的是可执行程序的名称 后面是所需要的 source 文件)
add_executable(Tutorial tutorial.cpp)
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
解释:
-
函数
-
configure_file():官方CMake教程对它的解释是:将文件复制到另一个位置并修改其内容。当然,这里的修改其内容也不是任意地修改,也是遵循一定的规则:将input文件复制到output文件,并在输入文件内容中的变量,替换引用为@VAR@或 V A R 的 变 量 值 。 每 个 变 量 引 用 将 替 换 为 该 变 量 的 当 前 值 , 如 果 未 定 义 该 变 量 , 则 为 空 字 符 串 。 可 能 有 些 绕 头 , 再 浅 显 一 点 : c o n f i g u r e f i l e , 复 制 一 份 输 入 文 件 到 输 出 文 件 , 替 换 输 入 文 件 中 被 @ V A R @ 或 者 {VAR}的变量值。每个变量引用将替换为该变量的当前值,如果未定义该变量,则为空字符串。可能有些绕头,再浅显一点:configure_file,复制一份输入文件到输出文件,替换输入文件中被@VAR@或者 VAR的变量值。每个变量引用将替换为该变量的当前值,如果未定义该变量,则为空字符串。可能有些绕头,再浅显一点:configurefile,复制一份输入文件到输出文件,替换输入文件中被@VAR@或者{VAR}引用的变量值。也就是说,让普通文件,也能使用CMake中的变量。
configure_file(<input> <output> [COPYONLY] [ESCAPE_QUOTES] [@ONLY] [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
-
target_include_directories():指定目标包含的头文件路径
-
内置变量
-
PROJECT_BINARY_DIR:全路径/build
-
PROJECT_SOURCE_DIR:全路径/代码在的地方
-
CMAKE_CXX_STANDARD_REQUIRED:可以为每个 Target 初始化
CXX_STANDARD_REQUIRED
属性。而 CXX_STANDARD_REQUIRED 存在的目的是如果用户没有对自己的 CXX_STANDARD 作出宣告的话,那它就会死——但set(CMAKE_CXX_STANDARD 17)
可以令这些措施一律无意义。这是为了能够对编译器的C++标准兼容性进行更好的约束,但对绝大多数人来说毫无意义。
tutorial.cpp 如下
// Copyright (c) 2022 Xiguan Inc
// Author: xiguan
// Email: xiguan.teng@qq.com
// Create on 22-12-2
// TODO:
//
#include <cmath>
#include <iostream>
#include "TutorialConfig.h"
using namespace std;
int main(int argc, char *argv[]) {
if (argc < 2) {
cout << argv[0] << "Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << endl;
cout << "Usage: " << argv[0] << " number" << endl;
return 1;
}
const double inputValue = ::std::stod(argv[1]);
const double outputValue = ::sqrt(inputValue);
cout << "The square root of " << inputValue << " is " << outputValue << endl;
return 0;
}
TutorialConfig.h.in 如下:
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
step2 添加库
现在给项目添加库(library),在库中实现平方根函数
文件目录结构如下:
编写顶层 CMakeLists.txt 如下:
# cmake 要求的最小版本
cmake_minimum_required(VERSION 3.10)
# 设置项目名称 可以设置版本号
project(Tutorial VERSION 1.0)
# 设置 c++ 的语言标准 C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(TutorialConfig.h.in TutorialConfig.h)
# 设置 MyFunctions 可选
option(USE_MYMATH "Use tutorial provided math implementation" ON)
if (USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif ()
## 添加库
#add_subdirectory(MathFunctions)
# 添加可执行程序(前面的是可执行程序的名称 后面是所需要的 source 文件)
add_executable(Tutorial tutorial.cpp)
target_link_libraries(Tutorial PUBLIC "${EXTRA_LIBS}")
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}" "${EXTRA_INCLUDES}")
# target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/MathFunctions")
# 链接这个库
# target_link_libraries(Tutorial PUBLIC MathFunctions)
解释:
-
函数
-
option:用于控制编译流程,相当于C语言中的宏条件编译
option(<variable> "<help_text>" [value])
variable:定义选项名称;help_text:说明选项的含义;value:定义选项默认状态,一般是OFF或者ON,除去ON之外,其他所有值都为认为是OFF。
-
target_link_libraries:将之前打包的库,链接到生成的目标上,不然会出现光声明,没定义的错误,注意也可以直接指定库名,如
target_link_libraries(main XXX.so)
或target_link_libraries(main XXX.a)
。 -
add_subdirectory:添加一个子目录并构建该子目录
add_subdirectory (source_dir [binary_dir] [EXCLUDE_FROM_ALL])
source_dir
必选参数。该参数指定一个子目录,子目录下应该包含CMakeLists.txt
文件和代码文件。子目录可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前目录的一个相对路径。binary_dir
可选参数。该参数指定一个目录,用于存放输出文件。可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前输出目录的一个相对路径。如果该参数没有指定,则默认的输出目录使用source_dir
。EXCLUDE_FROM_ALL
可选参数。当指定了该参数,则子目录下的目标不会被父目录下的目标文件包含进去,父目录的CMakeLists.txt
不会构建子目录的目标文件,必须在子目录下显式去构建。例外情况:当父目录的目标依赖于子目录的目标,则子目录的目标仍然会被构建出来以满足依赖关系(例如使用了target_link_libraries)
。 -
list:
list (subcommand <list> [args...])
subcommand
为具体的列表操作子命令,例如读取
、查找
、修改
、排序
等。<list>
为待操作的列表
变量,[args...]
为对列表
变量操作需要使用的参数表,不同的子命令对应的参数也不一致。
编写 MathFunctions CMakeLists.txt 如下
# 生成库
add_library(MathFunctions mysqrt.cpp)
解释:
- 函数
- 将指定的一些源文件打包成动态库和静态库,第一个参数就是生成库的名字,第二个参数是生成库的类型,后面的参数就都是源文件了,可以是之前定义的列表,也可以用
1.cpp 2.cpp 3.cpp
去指定。
tutorial.cpp 如下
// Copyright (c) 2022 Xiguan Inc
// Author: xiguan
// Email: xiguan.teng@qq.com
// Create on 22-12-2
// TODO:
//
#include <cmath>
#include <iostream>
#include "TutorialConfig.h"
#ifdef USE_MYMATH
#include "MathFunctions.h"
#endif
using namespace std;
int main(int argc, char *argv[]) {
if (argc < 2) {
cout << argv[0] << "Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << endl;
cout << "Usage: " << argv[0] << " number" << endl;
return 1;
}
const double inputValue = ::std::stod(argv[1]);
#ifdef USE_MYMATH
const double outputValue = mysqrt(inputValue);
#else
const double outputValue = ::sqrt(inputValue);
#endif
cout << "The square root of " << inputValue << " is " << outputValue << endl;
return 0;
}
TutorialConfig.h.in 如下:
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#cmakedefine USE_MYMATH
MathFunctions 目录
这个目录的文件就是自己实现了一下 mysqrt 这个函数
step3 为库添加使用要求
使用要求库对库和可执行程序的链接,包含命令行提供了更好的控制,也使 CMake 内传递目标属性更加可控