CMake入门教程

CMake入门教程

Archer阿澈 Lv1

简介

CMake 是一个元构建系统(Meta-Build System)。作为一个适配器为使用不同平台环境和工具链的开发者提供了一套统一的构建规范,并且为C++项目的依赖管理和模块化带来了极大的便利。为了更熟练的构建C++工程,掌握CMake的基本用法是必须的,本文章主要介绍在Windows平台下使用Visual Studio工具链进行项目构建的方法

元构建系统(Meta-Build System)

元构建系统是一种用于自动化生成构建文件(用于Makefile,ninja等build-system)的工具。

元构建系统(Meta-Build System)和构建系统(Build System)以及构建文件之间的关系:

  • 元构建系统:生成其他构建系统的工具。本身不执行构建工作,而是从更高层次的抽象描述构建依赖关系,并转换为make等更底层的构建系统。元构建系统会屏蔽掉平台相关依赖,具有很好的跨平台特性。
  • 构建系统:从源代码生成用户可以使用的目标文件的自动化工具。目标可以是库文件、可执行文件或者脚本等。构建系统通过构建文件定义编译规则,并调用工具链来编译代码。Make就是一个常见的构建系统。
  • 构建文件:用于定义构建系统编译规则的脚本,包含如何编译和链接程序的规则以及文件之间的依赖关系。

本教程假定你已经对C++的基础用法以及编译模型有一定了解,并非为C++初学者准备。

开发环境

教程中使用的开发环境。

  • Win11
  • Visual Studio 2022
  • CMake 3.27.6
  • Ninja
  • Clang-cl/llvm
  • C++ standard 17

基础用法

1. 构建可执行文件

先从VS2022创建一个空的CMake项目,简单修改目录格式如下:

1
2
3
4
5
6
│  CMakeLists.txt
│ CMakePresets.json
├─bin
├─include
├─out
└─source

CMakeLists.txtCMakePresets.json均为CMake项目模板自动生成,暂时先关注CMakeLists.txt中的内容,CMakePresets.json用于配置更顶层的环境参数,我们放到后面解释。

现在我们开始编写简单的工程代码,假设此时我们想要设计一个数据结构,它的接口如下:
dsu.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#pragma once

#include <numeric>
#include <vector>

class dsu {
public:
explicit dsu(size_t size);

void unite(size_t x, size_t y);

void move(size_t x, size_t y);

public:
size_t get_size(size_t x) { return size_[find(x)]; }

bool connected(size_t x, size_t y) { return find(x) == find(y); }

public:
size_t find(size_t x) { return pa_[x] == x ? x : pa_[x] = find(pa_[x]); }

private:
std::vector<size_t> pa_;
std::vector<size_t> size_;
std::vector<size_t> sum_;
};

它的实现在dsu.cpp中:
dsu.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "dsu/dsu.h"

dsu::dsu(size_t size)
: pa_(size * 2), size_(size * 2, 1), sum_(size * 2)
{
iota(pa_.begin(), pa_.begin() + size, size);
iota(pa_.begin() + size, pa_.end(), size);
std::iota(sum_.begin() + size, sum_.end(), 0);
}

void dsu::unite(size_t x, size_t y)
{
x = find(x);
y = find(y);
if (x == y) return;
if (size_[x] < size_[y])
std::swap(x, y);
pa_[y] = x;
size_[x] += size_[y];
sum_[x] += sum_[y];
}

void dsu::move(size_t x, size_t y)
{
auto fx = find(x);
auto fy = find(y);
if (fx == fy) return;
pa_[x] = fy;
--size_[fx];
++size_[fy];
sum_[fx] -= x;
sum_[fy] += x;
}

我们在main.cpp中使用这个工具:
main.cpp

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

#include "dsu.h"

int main()
{
dsu d(10);
d.unite(2, 3);
std::cout << d.get_size(2) << std::endl;
return 0;
}

目前的文件结构如下:

1
2
3
4
5
6
7
8
9
│  CMakeLists.txt
│ CMakePresets.json
├─bin
├─include
dsu.h
├─out
└─source
dsu.cpp
main.cpp

如何让main.cppdsu.cpp找到dsu.h并且生成一个可执行程序?对应的CMake代码如下:

1
2
3
4
5
6
7
8
cmake_minimum_required(VERSION 3.27.6) # 指定CMake版本下限
project(Utils) # 将项目命名为Utils
set(CMAKE_CXX_STANDARD 17) # 设置C++标准为C++17
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/)
# 修改内置变量“可执行程序输出目录”的值
include_directories(${CMAKE_SOURCE_DIR}/include) # 指定头文件目录
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp) # 将source目录下的所有源文件存储为列表写入到SRC_LIST中。
add_executable(app ${SRC_LIST})

接下来详细解释涉及到的命令:

  • cmake_minimum_required():用于指定CMake版本下限,是必须被调用的指令(cmake_minimum_required()必须在project()之前被调用)。

  • project():用于定义工程属性,是必须被调用的指令。完整格式为:

    1
    2
    3
    4
    5
    project(<工程名称>
    [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
    [DESCRIPTION <描述>]
    [HOMEPAGE_URL <主页URL>]
    [LANGUAGES <支持语言>...])
  • set():用于定义或修改CMake变量(包括用户创建变量和内置变量),完整格式为:

    1
    set(<variable> <value>... [PARENT_SCOPE] [CACHE <type> <docstring> [FORCE]])
    • <variable>:要设置的变量名。
    • <value>:变量的值,可以是单个值或多个值(列表)。
    • PARENT_SCOPE:将变量值设置到父作用域(通常是调用 add_subdirectory() 的上层 CMakeLists.txt)。
    • CACHE <type> <docstring> [FORCE]:将变量存入 CMake 缓存,使其可在 ccmakecmake-gui 中修改。
  • include_directories():用于指定头文件搜索路径的命令,这一命令会影响后续构建的所有目标(针对单个目标的版本为target_include_directories())。它会告诉编译器在哪些目录中查找 #include 指令引用的头文件。完整格式为:

    1
    include_directories([AFTER|BEFORE] [SYSTEM] <目录>...)
    • <目录>:头文件所在的路径,可以是绝对路径或相对路径。
    • AFTER(默认):把路径添加到系统默认搜索路径之后。
    • BEFORE:把路径添加到系统默认搜索路径之前,优先查找。
    • SYSTEM:标记目录为系统头文件目录,这样编译时不会针对这些目录的头文件生成警告。
  • file(GLOB) / file(GLOB_RECURSE)file(GLOB)用于获取匹配特定模式的文件列表并写入到指定变量,file(GLOB_RECURSE)则是的递归版本(file()函数还有很多用法,放在后面详细介绍)。完整格式为:

    1
    file(GLOB/GLOB_RECURSE <变量> <匹配模式>)
  • add_executable():用于创建可执行文件的命令,完整格式为:

    1
    add_executable(<目标名> <源文件1> <源文件2> ... <源文件N>)

2. 构建库文件

在工程中也时常会有制作库文件将项目模块化的需求,接下来介绍静态库和动态库的制作和使用方法。在本文的例子中,假设我们需要将dsu这个工具制作为库文件。
首先我们对项目结构稍加修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
│  CMakeLists.txt
│ CMakePresets.json
├─bin
├─include
│ └─dsu
dsu.h
├─libs
├─out
└─source
├─dsu
dsu.cpp
└─test
main.cpp

我们需要将source/dsu目录下的源文件编译到库文件,将source/test目录下的源文件编译为可执行文件。

对于静态库,具体的CMake代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cmake_minimum_required(VERSION 3.27.6)

project(Utils)

set(CMAKE_CXX_STANDARD 17)

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/)
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/) # 设置库文件的输出路径

include_directories(${CMAKE_SOURCE_DIR}/include)

file(GLOB DSU_SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/source/dsu/*.cpp)
file(GLOB TEST_SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/source/test/*.cpp)

add_library(dsu STATIC ${DSU_SRC_LIST}) # 创建静态库

add_executable(test ${TEST_SRC_LIST})
target_link_libraries(test PUBLIC dsu) # 将库链接到可执行文件

对于动态库,具体的CMake代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cmake_minimum_required(VERSION 3.27.6)

project(Utils)

set(CMAKE_CXX_STANDARD 17)

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/)
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/)

include_directories(${CMAKE_SOURCE_DIR}/include)

file(GLOB DSU_SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/source/dsu/*.cpp)
file(GLOB TEST_SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/source/test/*.cpp)

add_library(dsu SHARED ${DSU_SRC_LIST}) # 创建动态库

add_executable(test ${TEST_SRC_LIST})
target_link_libraries(test PUBLIC dsu)

由于Windows平台的特性,在本文的例子中,制作动态库时还需要将dsu的对应接口标记为__declspec(dllexport) / __declspec(dllimport)方能正常链接。

接下来详细解释涉及到的命令:

  • add_library():用于创建静态库或动态库,完整格式为:

    1
    add_library(<target> [STATIC | SHARED | MODULE | OBJECT] [EXCLUDE_FROM_ALL] <source1> [<source2> ...])
    • <target>:库的名称,后续可以用 target_link_libraries() 进行链接。
    • [STATIC | SHARED | MODULE | OBJECT]
      • STATIC(默认):生成 .lib(Windows)文件(静态库)。
      • SHARED:生成 .dll(Windows)文件(动态库)。
      • MODULE:生成插件库,类似 SHARED,但不会被默认链接。
      • OBJECT:生成对象文件 .obj,但不生成最终的 .lib.dll
    • [EXCLUDE_FROM_ALL]
      • 可选,如果添加该选项,则不会默认构建这个库,除非有其他目标显式依赖它。
    • <source1> [<source2> ...]
      • 需要编译到库中的源文件。
  • target_link_libraries():用于为一个目标(CMake中的target指的是可执行文件或库文件)指定它依赖的库。这个指令会影响链接阶段,确保目标能够正确地找到并使用指定的库。其完整格式如下:

    1
    target_link_libraries(<target> [<mode>] <library> [<library>...])
    • <target>:要链接库的目标(可执行文件或库)。
    • <mode>(可选):指定链接的可见性,可选值为 PRIVATEPUBLICINTERFACE
    • <library>:要链接的库,可以是已有的 CMake 目标、外部库文件、系统库等。
      其中可见性会影响模块的依赖传递和封装性,具体情况放在后面进行详细讨论。

3.多目标构建

一个大型项目中会有很多库文件和可执行文件,这些目标通常作为独立模块在项目中复用,并且分散在不同的源码目录中。如果继续在同一个CMakeLists.txt中处理所有目标的构建,则无法满足项目的模块化需求,CMake提供了嵌套CMake的方法来方便的处理这种情况。
对项目结构进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
│  CMakeLists.txt
│ CMakePresets.json
├─bin
├─include
│ ├─algorithm
algorithm.h
│ └─dsu
dsu.h
├─out
└─source
├─algorithm
CMakeLists.txt
connected_comps.cpp
kruskal.cpp
├─dsu
CMakeLists.txt
dsu.cpp
└─test
CMakeLists.txt
test1.cpp
test2.cpp
  • 项目需求:利用dsu模块实现algorithm模块中的两个算法,并完成test模块中的两个testbench。
  • 构建需求:将dsu模块构建为动态库,algorithm模块构建为静态库,test模块每个源文件单独构建为可执行程序。
    根目录下的CMakeLists.txt中的代码非常简单:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    cmake_minimum_required(VERSION 3.27.6)
    project(Utils)

    set(CMAKE_CXX_STANDARD 17)

    # 注意此处使用的是include_directories & link_directories,因为本文例子中所有目标使用的头文件路径和库链接路径是相同的。如果不同目标使用的路径不同,则需要使用target_include_directories & link_directories
    include_directories(${CMAKE_SOURCE_DIR}/include)
    link_directories(${CMAKE_SOURCE_DIR}/bin)

    # 添加CMake子目录
    add_subdirectory(source/dsu)
    add_subdirectory(source/algorithm)
    add_subdirectory(source/test)
    其中,add_subdirectory() 命令主要用于在 CMake 构建系统中添加子目录,并处理该目录下的 CMakeLists.txt 文件。是 CMake 工程组织多个模块,实现代码复用的关键命令。
    其完整格式为:
    1
    add_subdirectory(<source_dir> [binary_dir] [EXCLUDE_FROM_ALL])
  • <source_dir>必填,指定子目录的源代码路径,该目录必须包含 CMakeLists.txt
  • [binary_dir]:可选,指定子目录的构建目录(默认使用 CMake 指定的 build 目录)。
  • [EXCLUDE_FROM_ALL]:可选,如果指定,则该目录的构建不会包含在 all 目标中,只有手动构建时才会编译。

关于子目录的处理方式有一些特性:

  • 递归解析 CMakeLists.txt:进入子目录后,会解析该目录的 CMakeLists.txt
  • 继承变量作用域:默认情况下,父 CMakeLists.txt 中定义的变量对子目录可见(但子目录修改的变量不会影响父目录,除非使用 PARENT_SCOPE)。
  • 继承 include_directories()link_directories():父目录设置的 include_directories() 也适用于子目录。

至于各个子目录中的 CMakeLists.txt 文件,读者可以先尝试自行编写,此处列出一种编写方式:

  • source/dsu
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    cmake_minimum_required(VERSION 3.27.6)
    project(Dsu)

    set(CMAKE_CXX_STANDARD 17)

    file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

    add_library(dsu SHARED ${SRC_LIST})

    set_target_properties(dsu PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
  • source/algorithm
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    cmake_minimum_required(VERSION 3.27.6)
    project(Algorithm)

    set(CMAKE_CXX_STANDARD 17)

    file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

    add_library(algorithm STATIC ${SRC_LIST})

    set_target_properties(algorithm PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")

    target_link_libraries(algorithm PUBLIC dsu)
  • source/test
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    cmake_minimum_required(VERSION 3.27.6)
    project(Test)

    set(CMAKE_CXX_STANDARD 17)

    add_executable(test1 test1.cpp)
    set_target_properties(test1 PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
    target_link_libraries(test1 PUBLIC dsu)

    add_executable(test2 test2.cpp)
    set_target_properties(test2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
    target_link_libraries(test2 PUBLIC algorithm)

上面的实现使用了set_target_properties()命令,针对单一目标的属性(如库文件或可执行文件的输出路径)进行修改,而不是使用set()命令对这些属性进行全局范围的设置。对于实际的大型项目来说,使用前者更加合理;对于本文例子来说,两者并无差别。

4. 构建流程控制 TODO:

条件判断

CMake 提供了 if() 语句来执行条件分支。

1
2
3
4
5
6
7
if (condition)
# 代码块
elseif (condition)
# 代码块
else()
# 代码块
endif()

例如:

1
2
3
4
5
6
7
8
9
set(VALUE 10)

if (VALUE GREATER 5)
message("VALUE 大于 5")
elseif (VALUE EQUAL 5)
message("VALUE 等于 5")
else()
message("VALUE 小于 5")
endif()

输出:

1
VALUE 大于 5
条件 作用 示例
数值比较 进行数值大小判断 if (VALUE GREATER 5)
字符串比较 判断字符串是否相等 if ("Hello" STREQUAL "World")
变量是否定义 检查变量是否存在 if (DEFINED MY_VAR)
布尔值判断 检查变量的真假 if (MY_FLAG)
文件/目录存在性 判断文件或目录是否存在 if (EXISTS "path/to/file")
环境变量 检查环境变量是否存在 if (ENV{HOME})
逻辑运算 结合多个条件 if (A AND B), if (C OR D)

循环

  • foreach()
    用于遍历列表或范围。
1
2
3
foreach(variable RANGE start stop [step])
# 代码块
endforeach()
1
2
3
foreach(variable IN LISTS list_name)
# 代码块
endforeach()
1
2
3
foreach(variable item1 item2 item3 ...)
# 代码块
endforeach()

例如:

1
2
3
4
5
set(NAMES Alice Bob Charlie)

foreach(NAME IN LISTS NAMES)
message("Hello, ${NAME}!")
endforeach()

输出:

1
2
3
Hello, Alice!
Hello, Bob!
Hello, Charlie!

例如:

1
2
3
foreach(I RANGE 1 5)
message("Value: ${I}")
endforeach()

输出:

1
2
3
4
5
Value: 1
Value: 2
Value: 3
Value: 4
Value: 5

例如:

1
2
3
foreach(I RANGE 1 10 2)
message("Step: ${I}")
endforeach()

输出:

1
2
3
4
5
Step: 1
Step: 3
Step: 5
Step: 7
Step: 9
  • while()
    用于执行条件满足时的循环,适用于动态控制流。

    1
    2
    3
    while (condition)
    # 代码块
    endwhile()

    例如:

    1
    2
    3
    4
    5
    6
    set(COUNT 0)

    while (COUNT LESS 5)
    message("COUNT = ${COUNT}")
    math(EXPR COUNT "${COUNT} + 1")
    endwhile()

    输出:

    1
    2
    3
    4
    5
    COUNT = 0
    COUNT = 1
    COUNT = 2
    COUNT = 3
    COUNT = 4

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    set(LIST A B C D E)
    set(INDEX 0)

    while (INDEX LESS 5)
    list(GET LIST ${INDEX} ITEM)
    message("Item ${INDEX}: ${ITEM}")
    math(EXPR INDEX "${INDEX} + 1")
    endwhile()

    输出:

    1
    2
    3
    4
    5
    Item 0: A
    Item 1: B
    Item 2: C
    Item 3: D
    Item 4: E
  • break()continue()
    用于控制循环流程。

  • break():立即终止循环。

  • continue():跳过当前迭代,进入下一次循环。

应用

  • 跨平台编译
1
2
3
4
5
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
message("Building for Windows")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
message("Building for Linux")
endif()
  • 根据用户选项启用功能
1
2
3
4
5
option(ENABLE_TESTS "Enable testing" OFF)
if (ENABLE_TESTS)
enable_testing()
add_subdirectory(tests)
endif()

5. 外部模块管理 TODO:

提示

${}的使用 TODO:

场景 是否需要 ${} 示例
变量赋值 set(VAR "Hello")
变量访问 message(${VAR})
if() 判断 if(VAR)
作为命令参数 project(${VAR})
访问环境变量 message($ENV{HOME})
foreach() 遍历列表 否(遍历变量名) foreach(ITEM IN LISTS VAR)
unset() 删除变量 unset(VAR)

常用内置变量和宏 TODO:

1. 项目和构建相关变量

变量名 作用
CMAKE_SOURCE_DIR 项目源代码的根目录(顶层 CMakeLists.txt 所在目录)。
CMAKE_BINARY_DIR 项目的构建目录(cmake 执行的目录)。
CMAKE_CURRENT_SOURCE_DIR 当前处理的 CMakeLists.txt 文件所在的源目录。
CMAKE_CURRENT_BINARY_DIR 当前处理的 CMakeLists.txt 对应的二进制目录。
PROJECT_NAME project() 命令定义的项目名称。
CMAKE_PROJECT_NAME CMakeLists.txt 定义的项目名称(最顶层项目)。
CMAKE_VERSION CMake 的版本号,例如 3.26.0

2. CMake 目录和文件相关变量

变量名 作用
CMAKE_MODULE_PATH 指定 CMake 额外的模块搜索路径。
CMAKE_COMMAND CMake 执行命令的完整路径。
CMAKE_CURRENT_LIST_FILE 当前正在处理的 CMake 文件路径。
CMAKE_CURRENT_LIST_DIR 当前 CMake 文件所在的目录。

3. 编译器和编译相关变量

变量名 作用
CMAKE_C_COMPILER C 语言编译器路径。
CMAKE_CXX_COMPILER C++ 编译器路径。
CMAKE_C_FLAGS C 语言编译时的默认标志。
CMAKE_CXX_FLAGS C++ 编译时的默认标志。
CMAKE_BUILD_TYPE 指定构建类型(DebugReleaseRelWithDebInfoMinSizeRel)。
CMAKE_C_STANDARD 指定 C 语言标准(如 9911)。
CMAKE_CXX_STANDARD 指定 C++ 语言标准(如 11141720)。

4. 链接和库相关变量

变量名 作用
CMAKE_LINKER 链接器的路径。
CMAKE_EXE_LINKER_FLAGS 生成可执行文件时的链接选项。
CMAKE_SHARED_LINKER_FLAGS 生成动态库时的链接选项。
CMAKE_STATIC_LINKER_FLAGS 生成静态库时的链接选项。
CMAKE_LIBRARY_OUTPUT_DIRECTORY 目标库文件的输出目录。
CMAKE_ARCHIVE_OUTPUT_DIRECTORY 静态库的输出目录。

5. 目标平台相关变量

变量名 作用
CMAKE_SYSTEM_NAME 目标操作系统名称(如 WindowsLinuxDarwin)。
CMAKE_SYSTEM_VERSION 目标操作系统的版本。
CMAKE_HOST_SYSTEM_NAME CMake 运行的主机操作系统名称。
CMAKE_HOST_SYSTEM_VERSION CMake 运行的主机操作系统版本。
CMAKE_SIZEOF_VOID_P 指针的字节大小(可用于判断 32 位或 64 位)。

6. 生成器相关变量

变量名 作用
CMAKE_GENERATOR 指定的 CMake 生成器(如 NinjaUnix Makefiles)。
CMAKE_MAKE_PROGRAM make 命令路径(仅适用于 Makefile 生成器)。

7. 安装相关变量

变量名 作用
CMAKE_INSTALL_PREFIX install() 指定的默认安装路径。
CMAKE_INSTALL_BINDIR 可执行文件的安装目录(默认 bin/)。
CMAKE_INSTALL_LIBDIR 库文件的安装目录(默认 lib/)。
CMAKE_INSTALL_INCLUDEDIR 头文件的安装目录(默认 include/)。

8. 测试和构建系统相关变量

变量名 作用
BUILD_SHARED_LIBS 是否默认构建动态库(ON/OFF)。
CMAKE_VERBOSE_MAKEFILE 是否打印详细的 Makefile 过程(ON/OFF)。
CMAKE_EXPORT_COMPILE_COMMANDS 是否生成 compile_commands.json(用于 Clangd 等工具)。

file() 的常见操作 TODO:

操作 功能
GLOB 查找符合特定模式的文件
GLOB_RECURSE 递归查找符合模式的文件
WRITE 创建并写入文件
APPEND 追加内容到文件
READ 读取文件内容
COPY 复制文件或目录
REMOVE 删除文件
REMOVE_RECURSE 递归删除文件夹及其内容
RENAME 重命名文件或目录
MAKE_DIRECTORY 创建目录
SIZE 获取文件大小
SHA256 计算文件 SHA256 哈希值
STRINGS 从文件中提取文本
TIMESTAMP 获取文件时间戳

CMake预设

CMakePresets.json文件定义了一系列的CMake预设信息,包括跨平台配置,编译器和生成器配置等。下面是是一个简单的CMakePresets.json样例以及对每个条目的解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
{
"version": 3,
"configurePresets": [
{
"name": "windows-base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang-cl.exe",
"CMAKE_CXX_COMPILER": "clang-cl.exe"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "x64-debug",
"displayName": "x64 Debug",
"inherits": "windows-base",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "x64-release",
"displayName": "x64 Release",
"inherits": "x64-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "linux-debug",
"displayName": "Linux Debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"vendor": {
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
}
}
},
{
"name": "macos-debug",
"displayName": "macOS Debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"vendor": {
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
}
}
}
]
}

  • windows-base:这是一个基础预设,被标记为隐藏(”hidden”: true),意味着它只可以被其他预设继承。它设置了Ninja生成器,指定了二进制和安装目录,并设置了C和C++编译器为cl.exe。此预设仅在平台为Windows时应用。
  • x64-debug 和 x64-release:这两个预设继承自windows-base,分别用于64位的Debug和Release构建。它们设置了体系结构为x64,并分别设置了CMake构建类型为Debug和Release。
  • linux-debug:这个预设专门用于Linux平台的Debug构建。它设置了Ninja生成器,指定了二进制和安装目录,并设置了构建类型为Debug。此预设仅在平台为Linux时应用。
  • macos-debug:这个预设专门用于macOS平台的Debug构建。配置方法与linux-debug类似。
  • Title: CMake入门教程
  • Author: Archer阿澈
  • Created at : 2023-05-04 17:47:34
  • Updated at : 2023-05-04 17:47:34
  • Link: https://www.archer-du.top/2023/05/04/Tech/Fundamentals/CMake_Tutorial/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments