生成构建文件Makefile
表示输出makefile文件的目录
表示试用clang++作为编译器
cmake -Bbuild -DCMAKE_CXX_COMPILER=clang++
cmake -Bbuild -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17
构建可执行文件,编译
cd build;make
或者make -C build,优点是:跨平台
或者cmake --build build
add_executable(输出的可执行文件 输入的多个源文件)
add_executable(a.out main.cpp hello.cpp)
add_library(test STATIC source1.cpp source2.cpp) # 生成静态库 libtest.a
add_library(test SHARED source1.cpp source2.cpp) # 生成动态库 libtest.so
创建库以后,要在某个可执行文件中使用该库,只需要:
target_link_libraries(myexec PUBLIC test) # 为 myexec 链接刚刚制作的库 libtest.a
有时候我们会有多个可执行文件,他们之间用到的某些功能是相同的,我们想把这些共用的功能做成一个库,方便大家一起共享.


Windows:
Linux:
CMake 除了 add_executable 可以生成可执行文件外,还可以通过 add_library 生成库文件。
add_library 的语法与 add_executable 大致相同,除了他需要指定是动态库还是静态库:
add_library(test STATIC source1.cpp source2.cpp) # 生成静态库 libtest.a
add_library(test SHARED source1.cpp source2.cpp) # 生成动态库 libtest.so
target_link_libraries(myexec PUBLIC test) # 为 myexec 链接刚刚制作的库 libtest.a
其中 PUBLIC 的含义稍后会说明(CMake 中有很多这样的大写修饰符)



在多文件编译章中,说到了需要在 main.cpp 声明 hello() 才能引用。为什么?
其实,C++ 是一种强烈依赖上下文信息的编程语言,

问题:如果能只写一遍,然后自动插入到需要使用hello()的地方

头文件 - 批量插入几行代码的硬核方式

递归地使用头文件


复杂的工程中,我们需要划分子模块,通常一个库一个目录,比如:


因为 hello.h 被移到了 hellolib 子文件夹里,因此 main.cpp 里也要改成

add_executable(a.out main.cpp)
target_link_libraries(a.out PUBLIC hellolib)
target_include_directories(a.out PUBLIC hellolib)
这样甚至可以用 <hello.h> 来引用这个头文件了,因为通过 target_include_directories 指定的路径会被视为与系统路径等价:

总结:course/01/10/main.cpp
#include <cstdio>
//方式1
#include "hellolib/hello.h"
//方式2
//#include "hello.h" or #include <hello.h>
//CMake中增加# target_include_directories(a.out PUBLIC hellolib)
int main() {
hello();
return 0;
}
add_library(hellolib STATIC hello.cpp)
target_include_directories(hellolib PUBLIC .)
除了头文件搜索目录以外,还有这些选项,PUBLIC 和 PRIVATE 对他们同理:
target_include_directories(myapp PUBLIC /usr/include/eigen3) # 添加头文件搜索目录
target_link_libraries(myapp PUBLIC hellolib) # 添加要链接的库
target_add_definitions(myapp PUBLIC MY_MACRO=1) # 添加一个宏定义,等价于#define MY_MACRO 1
target_add_definitions(myapp PUBLIC -DMY_MACRO=1) # 与 MY_MACRO=1 等价
target_compile_options(myapp PUBLIC -fopenmp) # 添加编译器命令行选项
target_sources(myapp PUBLIC hello.cpp other.cpp) # 添加要编译的源文件
以及可以通过下列指令(不推荐使用),把选项加到所有接下来的目标去:
include_directories(/opt/cuda/include) # 给所有的目标添加头文件搜索目录
link_directories(/opt/cuda) # 给所有的目标添加库文件的搜索路径
add_definitions(MY_MACRO=1) #给所有的目标添加一个宏定义
add_compile_options(-fopenmp) #给所有的目标添加编译器命令行选项
有时候我们不满足于 C++ 标准库的功能,难免会用到一些第三方库。
nothings/stb - 大名鼎鼎的 stb_image 系列,涵盖图像,声音,字体等,只需单头文件!
Neargye/magic_enum - 枚举类型的反射,如枚举转字符串等(实现方式很巧妙)
g-truc/glm - 模仿 GLSL 语法的数学矢量/矩阵库(附带一些常用函数,随机数生成等)
Tencent/rapidjson - 单纯的 JSON 库,甚至没依赖 STL(可定制性高,工程美学经典)
ericniebler/range-v3 - C++20 ranges 库就是受到他启发(完全是头文件组成)
fmtlib/fmt - 格式化库,提供 std::format 的替代品(需要 -DFMT_HEADER_ONLY)
gabime/spdlog - 能适配控制台,安卓等多后端的日志库(和 fmt 冲突!)

第二友好的方式则是作为 CMake 子模块引入,也就是通过 add_subdirectory。
fmtlib/fmt - 格式化库,提供 std::format 的替代品
gabime/spdlog - 能适配控制台,安卓等多后端的日志库
ericniebler/range-v3 - C++20 ranges 库就是受到他启发
g-truc/glm - 模仿 GLSL 语法的数学矢量/矩阵库
abseil/abseil-cpp - 旨在补充标准库没有的常用功能
bombela/backward-cpp - 实现了 C++ 的堆栈回溯便于调试
google/googletest - 谷歌单元测试框架
google/benchmark - 谷歌性能评估框架
glfw/glfw - OpenGL 窗口和上下文管理
libigl/libigl - 各种图形学算法大合集



可以通过 find_package 命令寻找系统中的包/库:
find_package(fmt REQUIRED)
target_link_libraries(myexec PUBLIC fmt::fmt)
现代 CMake 认为一个包 (package) 可以提供多个库,又称组件 (components),比如 TBB 这个包,就包含了 tbb, tbbmalloc, tbbmalloc_proxy 这三个组件。
因此为避免冲突,每个包都享有一个独立的名字空间,以 :: 的分割(和 C++ 还挺像的)。
你可以指定要用哪几个组件:
find_package(TBB REQUIRED COMPONENTS tbb tbbmalloc REQUIRED)
target_link_libraries(myexec PUBLIC TBB::tbb TBB::tbbmalloc)
fmt::fmt
spdlog::spdlog
range-v3::range-v3
TBB::tbb
OpenVDB::openvdb
Boost::iostreams
Eigen3::Eigen
OpenMP::OpenMP_CXX
Linux 可以用系统自带的包管理器(如 apt)安装 C++ 包。
pacman -S fmt

set -e
git clone https://github.com/microsoft/vcpkg.git --depth=1
rm -rf build
cmake -B build -DCMAKE_TOOLCHAIN_FILE="$PWD/vcpkg/scripts/buildsystems/vcpkg.cmake"
cmake --build build --target a.out
cd vcpkg
sh bootstrap-vcpkg.sh
./vcpkg install fmt:x64-linux
cd ..
build/a.out