Parallel201-1.现代CMake进阶指南
Parallel201 笔记+课后作业,课程传送门:
命令行小技巧
古代 CMake 指的是 CMake2.x 版本,现代 CMake 已经到了 3.x 版本,许多地方得到了简化
PS:本文提到的构建一般指编译
CMake 命令行构建流程(-B)
CMake 2.x
1 | mkdir -p build |
CMake 3.x
1 | cmake -B build #在build目录下生成makefile、.slu等 |
指定配置变量(-D、-G)
cmake -B build 为配置阶段, 生成 makefile、.slu, 在这个阶段可以指定一些生成规则
-D
:设置缓存变量, 下一次 cmake -B build 时, 之前的 -D 添加仍然会被保留
格式: -D VAR=VAL
1 | #使用Release模式构建 |
-G
:指定使用的构建系统
1 | #使用Ninja来进行构建 |
Ninja 是现代化的构建系统, 跨平台, 可多核心构建, 速度优于 make;但是 CUDA toolkit 在 windows 上只允许用 MSBuild 进行构建
添加源文件
目录结构:
1 | -------------------- |
添加一个可执行文件 main 为构建目标, main 由 main.cpp 构建而成
1 | add_executable(main main.cpp) |
或者先添加一个可执行文件, 然后添加源文件
1 | add_executable(main main.cpp) |
多个源文件
目录结构:
1 | -------------------- |
一个个手动添加
1 | add_executable(main main.cpp other.cpp) |
通过变量的方式
1 | add_executable(main) |
main.cpp 中有#include "other.h"
所以上面不写 other.h 也是能正常构建的
但是写上更好, 写上之后 VS 的”Header Files”一栏就会出现 other.h 了
Tips:
- 变量相当于文本替换, 支持嵌套, 且字符串中的${}也会发生替换
GLOB 实现批量添加源文件
使用 GLOB 自动查找当前目录下指定扩展名的文件
GLOB 选项将会为所有匹配查询表达式的文件生成一个文件 list,并将该 list 存储进变量 variable 里
1 | add_executable(main) |
上面的 sources 变量只会在第一次 cmake -B build 时被赋值, 之后如果不更改 CMakeLists.txt, 它就一直不变, 即使创建了新的.cpp 文件
为了让它每次 cmake -B build 时都会更新, 加上 CONFIGURE_DEPENDS
1 | add_executable(main) |
另外 GLOB 只会搜索当前目录下的.cpp、.h, 如果源文件在子目录就不会被找到
需要写子目录的查询表达式
1 | add_executable(main) |
或者使用 GLOB_RECURSE, 这样会找到子目录下的.cpp、.h
但也会找到 build 目录下 cmake 构建时用于测试的临时.cpp 文件, 所以推荐将源码全放在 src 文件夹下, 然后使用 src/.cpp、src/.h
1 | #add_executable(main) |
文件名查询表达式与正则表达式类似。如果为一个表达式指定了 RELATIVE 标志,返回的结果将会是相对于给定路径的相对路径。
文件名查询表达式的例子:
1 | *.cxx - 匹配所有后缀名为 cxx 的文件 |
aux_source_directory 自动收集需要的文件后缀名
1 | add_executable(main) |
项目配置变量
CMAKE_BUILD_TYPE, 项目构建类型
1 | cmake_minimum_required(VERSION 3.15) |
项目构建类型与对应的编译器参数(以 g++为例)
Debug:
-O0 -g
Release:
-O3 -DNDEBUG
MinSizeRel:
-Os -DNDEBUG
RelWithDebInfo:
-O2 -g -DNDEBUG
NDEBUG 是一个 c 语言的一个宏, 如果#define NDEBUG 将会移除 assert(), -DNDEBUG 就相当于定义这个宏
这个写法就跟 cmake -B build -DVAR=VAL 一样
Tips: 如何设定变量的默认值
默认情况下, CMAKE_BUILD_TYPE 未指定的话会默认为 Debug, 若想默认为 Release:
1
2
3if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
project 初始化, 项目名
project 可以命名项目, 并把当前目录作为项目根目录, 并提供一系列可用的变量
PROJECT_NAME: 当前项目名
PROJECT_SOURCE_DIR: 当前项目源码目录, 表示最近一次调用 project 的 CMakeLists.txt 所在的源码目录
PROJECT_BINARY_DIR: 二进制文件的生成目录, 由
cmake -B
指定, PROJECT_BINARY_DIR 会变成指定的目录路径PROJECT_IS_TOP_LEVEL: 可以判断当前项目是不是顶层的项目, BOOL 类型
CMAKE_PROJECT_NAME: 根项目名
CMAKE_SOURCE_DIR: 根项目源码目录
CMAKE_BINARY_DIR: 根项目二进制文件生成目录
CMAKE_CURRENT_SOURCE_DIR: 当前 CMakeLists.txt 所在源码目录
CMAKE_CURRENT_BINARY_DIR: 当前 CMakeLists.txt 构建的二进制文件生成目录
详情:
可以在子模块里使用 project 命令, 将当前目录作为一个独立的子项目, 这样一来 PROJECT_SOURCE_DIR 就会是子模块的源码目录而不是外层了。CMake 会认为这个子模块是个独立的项目, 会额外做一些初始化, 他的构建目录 PROJECT_BINARY_DIR 也会变成 build/<源码相对路径>, 如在 MSVC 上会看见 build/mylib/mylib.vcxproj 的生成。
project 初始化, LANGUAGES 字段
指定项目所用的语言
1 | cmake_minimum_required(VERSION 3.15) |
支持的语言:
- C:C 语言
- CXX:C++语言
- ASM:汇编语言
- Fortran:古老的编程语言
- CUDA:英伟达的 CUDA(3.8 版本新增)
- OBJC:苹果的 Objective-C(3.16 版本新增)
- OBJCXX:苹果的 Objective-C++(3.16 版本新增)
- ISPC:一种因特尔的自动 SIMD 编程语言(3.18 版本新增)
- 如果不指定 LANGUAGES,默认为 C 和 CXX。
project 初始化, VERSION 字段
1 | cmake_minimum_required(VERSION 3.15) |
- project(项目名 VERSION x.y.z)可以把当前项目的版本号设定为 x.y.z
- 之后可以通过 PROJECT_VERSION 来获取当前项目的版本号
- PROJECT_VERSION_MAJOR 获取 x(主版本号)
- PROJECT_VERSION_MINOR 获取 y(次版本号)
- PROJECT_VERSION_PATCH 获取 z(补丁版本号)
project 初始化, 其他字段


定义PROJECT_DESCRIPTION
、PROJECT_HOMEPAGE_URL
变量


定义项目名_VERSION
、项目名_SOURCE_DIR
、项目名_BINARY_DIR
变量
设置 C++标准
为了跨平台不要使用set(CMAKE_CXX_FLAGS -std=c++17)
这种方式
1 | cmake_minimum_required(VERSION 3.15) |
cmake_minimum_required, 指定最低所需的 CMake 版本
1 | #最低需要cmake版本为3.15 |
使用cmake --version
指令可以获取当前 cmake 版本号
一份标准 CMakeLists.txt
1 | cmake_minimum_required(version 3.15) |
- 如果生成二进制文件的文件夹和存储源码的文件夹是同一个文件夹, 那么将会产生警告
- 默认使用 Release 模式构建
- 标准库在
头中定义了两个模板函数 std::min() 和 std::max()
但在 windows 上无法使用,因为 windows 的<windows.h>中定义了两个传统的宏 min/max, 所以用-DNOMINMAX 来去除定义 - 如果可以的话使用 ccache 来加速编译
CMake 常见变量——Project 和 CMake 相关信息
链接库文件
链接库可以简单理解为里面包含了一系列的函数, 你可以方便的在自己的项目里调用他们, 只要引入了对应的头文件(函数声明)
Parallel201-1.现代CMake进阶指南
https://fly.meow-2.com/post/note/parallel/Parallel201-1.html