Parallel201 笔记 + 课后作业,课程传送门:
命令行小技巧
古代 CMake 指的是 CMake2.x 版本,现代 CMake 已经到了 3.x 版本,许多地方得到了简化
PS:本文提到的构建一般指编译
CMake 命令行构建流程 (-B)
CMake 2.x
mkdir -p build
cd build
cmake .. #依据上层目录的CMakeLists.txt在build目录下生成makefile、.slu等
make -j4 #make根据makefile四核心并行构建可执行文件
sudo make install #make根据makefile将生成的文件放到指定的位置
#make clean 可以清除make生成的构建文件
CMake 3.x
cmake -B build #在build目录下生成makefile、.slu等
cmake --build build -j4 #make -C build -j4, build为makefile所在目录, windows上会调用别的构建系统
cmake --build build --target install
指定配置变量 (-D、-G)
cmake -B build 为配置阶段,生成 makefile、.slu, 在这个阶段可以指定一些生成规则
-D
:设置缓存变量,下一次 cmake -B build 时,之前的 -D 添加仍然会被保留
格式:-D VAR=VAL
#使用Release模式构建
cmake -B build -DCMAKE_BUILD_TYPE=Release
#指定安装路径/opt/openvdb-8.0(会安装到 /opt/openvdb-8.0/lib/libopenvdb.so)
cmake -B build -DCMAKE_INSTALL_PREFIX=/opt/openvdb-8.0
-G
:指定使用的构建系统
#使用Ninja来进行构建
cmake -GNinja -B build
Ninja 是现代化的构建系统,跨平台,可多核心构建,速度优于 make;但是 CUDA toolkit 在 windows 上只允许用 MSBuild 进行构建
添加源文件
目录结构:
--------------------
- main.cpp
- CMakeLists.txt
添加一个可执行文件 main 为构建目标,main 由 main.cpp 构建而成
add_executable(main main.cpp)
或者先添加一个可执行文件,然后添加源文件
add_executable(main main.cpp)
target_sources(main PUBLIC main.cpp)
多个源文件
目录结构:
--------------------
- main.cpp
- other.cpp
- other.h
- CMakeLists.txt
一个个手动添加
add_executable(main main.cpp other.cpp)
通过变量的方式
add_executable(main)
set(sources main.cpp other.cpp)
target_sources(main PUBLIC ${sources})
main.cpp 中有#include "other.h"
所以上面不写 other.h 也是能正常构建的
但是写上更好,写上之后 VS 的"Header Files"一栏就会出现 other.h 了
Tips:
- 变量相当于文本替换,支持嵌套,且字符串中的${}也会发生替换
GLOB 实现批量添加源文件
使用 GLOB 自动查找当前目录下指定扩展名的文件
GLOB 选项将会为所有匹配查询表达式的文件生成一个文件 list,并将该 list 存储进变量 variable 里
add_executable(main)
file(GLOB sources *.cpp *.h)
target_sources(main PUBLIC ${sources})
上面的 sources 变量只会在第一次 cmake -B build 时被赋值,之后如果不更改 CMakeLists.txt, 它就一直不变,即使创建了新的.cpp 文件
为了让它每次 cmake -B build 时都会更新,加上 CONFIGURE_DEPENDS
add_executable(main)
file(GLOB sources CONFIGURE_DEPENDS *.cpp *.h)
target_sources(main PUBLIC ${sources})
另外 GLOB 只会搜索当前目录下的.cpp、.h, 如果源文件在子目录就不会被找到
需要写子目录的查询表达式
add_executable(main)
file(GLOB sources CONFIGURE_DEPENDS *.cpp *.h 子目录/*.cpp 子目录/*.h)
target_sources(main PUBLIC ${sources})
或者使用 GLOB_RECURSE, 这样会找到子目录下的.cpp、.h
但也会找到 build 目录下 cmake 构建时用于测试的临时.cpp 文件,所以推荐将源码全放在 src 文件夹下,然后使用 src/.cpp、src/.h
#add_executable(main)
#file(GLOB_RECURSE sources CONFIGURE_DEPENDS *.cpp *.h)
#target_sources(main PUBLIC ${sources})
add_executable(main)
file(GLOB_RECURSE sources CONFIGURE_DEPENDS src/*.cpp src/*.h)
target_sources(main PUBLIC ${sources})
文件名查询表达式与正则表达式类似。如果为一个表达式指定了 RELATIVE 标志,返回的结果将会是相对于给定路径的相对路径。
文件名查询表达式的例子:
*.cxx - 匹配所有后缀名为 cxx 的文件
*.vt? - 匹配所有后缀名为 vta,...,vtz 的文件
f[3-5].txt - 匹配 f3.txt, f4.txt, f5.txt 文件
aux_source_directory 自动收集需要的文件后缀名
add_executable(main)
aux_source_directory(. sources)
aux_source_directory(子目录 sources)
target_sources(main PUBLIC ${sources})
项目配置变量
CMAKE_BUILD_TYPE, 项目构建类型
cmake_minimum_required(VERSION 3.15)
project(hellocmake LANGUAGES CXX)
set(CMAKE_BUILD_TYPE Release)
add_executable(main main.cpp)
项目构建类型与对应的编译器参数 (以 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:
if (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 字段
指定项目所用的语言
cmake_minimum_required(VERSION 3.15)
project(hellocmake LANGUAGES CXX)
#或者, 这样可以把enable_language放到if里, 某些情况下才启用某些语言
#project(hellocmake LANGUAGES NONE)
#enable_language(CXX)
add_executable(main main.cpp)
支持的语言:
- 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 字段
cmake_minimum_required(VERSION 3.15)
project(hellocmake LANGUAGES CXX VERSION 1.2.3)
add_executable(main main.cpp)
- 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)
这种方式
cmake_minimum_required(VERSION 3.15)
#使用C++17
set(CMAKE_CXX_STANDARD 17)
#如果编译器不支持C++17就报错, 设置为OFF, 不支持17的话会按14来编译
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#为了跨平台关闭GCC扩展语法
set(CMAKE_CXX_EXTENSIONS OFF)
project(hellocmake)
cmake_minimum_required, 指定最低所需的 CMake 版本
#最低需要cmake版本为3.15
#cmake_minimum_required(VERSION 3.15)
#需要cmake版本为3.15到3.20
cmake_minimum_required(VERSION 3.15...3.22)
project(hellocmake)
使用cmake --version
指令可以获取当前 cmake 版本号
一份标准 CMakeLists.txt
cmake_minimum_required(version 3.15)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(zeno LANGUAGES C CXX)
if (PROJECT_BINARY_DIR STREQUAL PROJECT_SOURCE_DIR)
message(WARNING "The binary directory of CMake cannot be the same as source directory!")
endif()
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
# Set to True when the target system is Windows, including Win64.
if (WIN32)
# Add -D define flags to the compilation of source files.eg: gcc -DNOMINMAX
add_definitions(-DNOMINMAX -D_USE_MATH_DEFINES)
endif()
# Set to true when the compiler is some version of Microsoft Visual C++ or another compiler simulating the Visual C++ cl command-line syntax.
if (NOT MSVC)
find_program(CCACHE_PROGRAM ccache)
if (CCACHE_PROGRAM)
message(STATUS "Found CCache: ${CCACHE_PROGRAM}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PROGRAM})
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_PROGRAM})
endif()
endif()
- 如果生成二进制文件的文件夹和存储源码的文件夹是同一个文件夹,那么将会产生警告
- 默认使用 Release 模式构建
- 标准库在
<algorithm>
头中定义了两个模板函数 std::min() 和 std::max() 但在 windows 上无法使用,因为 windows 的<windows.h>
中定义了两个传统的宏 min/max, 所以用-DNOMINMAX 来去除定义 - 如果可以的话使用 ccache 来加速编译
CMake 常见变量——Project 和 CMake 相关信息
链接库文件
链接库可以简单理解为里面包含了一系列的函数,你可以方便的在自己的项目里调用他们,只要引入了对应的头文件 (函数声明)