尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

【软件开发】CMake学习笔记

【软件开发】CMake学习笔记
📅 发布时间:2026/6/19 1:07:29

【软件开发】CMake 学习笔记

CMake 是什么?

是构建系统(如 Visual Studio)的文件(如 .vcxproj .sln)的创建器,具体要生成的构建系统可以通过 CMakePresets 文件中的 generator 指定。

构建系统一般不是跨平台的,但 CMake 支持在不同的操作系统上生成不同的构建系统文件,通过这种包装的方式从而实现了 C++项目的跨平台。

构建系统

CMake 指令

https://cmake.org/cmake/help/latest/manual/cmake.1.html

# 基于目标位置的“cmake项目”生成“构建系统项目”
cmake <path>
# 编译目标位置的“构建系统项目”,输出其二进制文件[编译cmake项目中的自定义目标]
cmake --build <path> [--target <target>]
# 运行.cmake脚本并为脚本设置可选参数
cmake [-D <var>=<value>]... -P <cmakeScript>

CMakeLists 指令

CMakeLists.txt是生成 CMake 项目的说明文件,用专门的 CMake 语言编写,由于 CMake 也是一种编程语言,因此也支持判断循环等,此外还提供了很多便利的功能性指令。

CMakeLists.txt可以有多份,但每个文件夹至多能放一个,此外顶层CMakeLists.txt文件中的首条指令必须用于指定 CMake 版本,版本指令如下:

# 描述CMake的最低支持版本(顶层CMake文件必带)
cmake_minimum_required(VERSION <version>)

环境变量

CMake 中没有常规编程语言中的变量概念,所有中间数据都用环境变量存储。环境变量即一对字符串键值组,恰好充当变量名和变量值。用户可以自己设置环境变量,也可以获取系统的环境变量。

基本读写

# 设置环境变量[环境变量作用域扩大到父范围(默认为当前函数或目录)]
set(<varName> <varValue> [PARENT_SCOPE])
# 设置缓存变量(全局作用域,持久存储在磁盘)(必须设置FORCE,否则有缓存时不会设置)
set(<varName> <varValue>... CACHE <type> <docstring> FORCE)
# 获取环境变量(下方代码将被直接替换成环境变量值)(支持嵌套使用)
${<varName>}

编辑内容

环境变量本质就是字符串,可以采用 string、list、包括再次使用 set 等命令来编辑。另外针对非局部作用域变量的编辑还有几个注意点:

  1. 对缓存变量和父作用域变量编辑,只会修改以其为初值的局部变量,因此修改完必须再次显式设置为缓存变量。
  2. 缓存变量可以在构建 cmake 文件时从命令行设置 -D<var>=<value>,注意代码中也要 set 该缓存命令才行,但不要用 FORCE 关键字。

预设环境变量

CMake 系统预设的环境变量,用户可以从中读写一些重要的配置数据。

  • 编译环境

    1. CMAKE_CXX_STANDARD:项目中所用的 C++标准(数字,如 17、20)
    2. CMAKE_CXX_STANDARD_REQUIRED:指定的 C++标准是否是必须的,从而决定编译器不支持时是否停止生成(布尔值)
  • 项目信息

    1. <projectName>_VERSION_MAJOR:声明项目时额外提供的主版本号。
    2. <projectName>_VERSION_MINOR:声明项目时额外提供的次版本号。
  • 目录

    1. CMAKE_SOURCE_DIR:顶级 CMakeLists 的源目录。
    2. CMAKE_BINARY_DIR:顶级 CMakeLists 的构建目录。
    3. CMAKE_CURRENT_SOURCE_DIR:当前 CMakeLists 的源目录。
    4. CMAKE_CURRENT_BINARY_DIR:当前 CMakeLists 的构建目录。
    5. PROJECT_BINARY_DIR:上次调用project()的 CMakeLists 对应的构建目录。
    6. PROJECT_SOURCE_DIR:上次调用project()的 CMakeLists 对应的源目录。
    7. CMAKE_RUNTIME_OUTPUT_DIRECTORY:构建系统最终输出的二进制文件的目录。

    备注:指令 5、6 不受add_subdirectory()影响。

环境变量列表

CMake 中没有常规编程语言中数组的概念,相应的是改用“环境变量列表”代替。环境变量列表本质也是一个环境变量,其值也是一个字符串,但特别的是该值通常是由多个用“;”分隔的条目组成。

许多指令都支持环境变量列表作为输入来支持多参数,同时也配有专门的工具指令来编辑环境变量列表。

# 从变量列表中去除指定项
list(REMOVE_ITEM <list> <value> [<value> ...])
# 根据正则表达式过滤变量列表
list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regex>)
# 追加条目
list(APPEND <list> <value>)

流程控制

既然是编程语言,自然也支持逻辑控制。

条件执行

# 基本用法:[不]满足条件时执行
if([NOT] <bool>) \ endif()
# 比较变量的值(由于没有变量的概念,都是通过显式指定比较方式来比较)
if(<variableName> EQUAL <value>)
# 确认字符串是否满足指定的正则表达式
if(<var> MATCHES <regex>)
# 查看环境变量是否定义
if(DEFINED <variableName>)
# 确认路径是否存在
if(EXISTS <inputPath>)

遍历执行

# 遍历环境变量列表
foreach(<var> <list>) \ endforeach()

函数定义

既然是编程语言,自然也支持自定义函数。

# 定义一个宏函数
macro(<macroName> [inputVar]...) \ endmacro()

依赖处理

由于CMakeLists.txt可以有多份,甚至打包成模块,因此需要相关的指令处理依赖。

# 添加一个子目录(子目录需要带有CMakeLists)
add_subdirectory(<source_dir>)
# 寻找一个模块(带有特定配置文件的目录将会被识别为模块,可当成项目使用)
find_package(<packageName> CONFIG REQUIRED)

项目配置

CMakeLists.txt主要用于创建 C++项目,必然需要很多声明项目属性的指令。每个CMakeLists.txt文件中只能声明一个项目,当有多个项目时需要创建多份CMakeLists.txt。

基础配置

以下指令是创建一个项目必须要提供的。

# 创建一个项目
project(<projectName>)
# 声明项目的输出为可执行文件
add_executable(<projectName> <sourceFile>...)
# 声明项目的输出为静态/动态库文件
add_library(<projectName> [STATIC|SHARED] <sourceFile>...)
# 声明项目是特殊的无输出项目
add_custom_target(<projectName> SOURCES <sourceFile>...)

可选配置

可选的影响项目属性的配置

# 为项目添加附加包含目录
target_include_directories(<projectName> {PUBLIC|PRIVATE} <headerDir>...)
# 为项目添加附加库
target_link_libraries(<projectName> {PUBLIC|PRIVATE} {<projectName>|<libFile>...})
# 为项目添加预处理定义
target_compile_definitions(<projectName> {PUBLIC|PRIVATE} <definition>...)
# 为项目添加编译选项
target_compile_options(<option>...)
# 将项目分类到vs中的解决方案文件夹(3.26之前需先打开 USE_FOLDERS 功能)
set_target_properties(<projectName> PROPERTIES FOLDER <folderName>)
# 为项目设置编译事件(如下方为编译后执行某cmake脚本)
add_custom_command(TARGET ${target}POST_BUILDCOMMAND cmake -D target=${target} -P script.cmake
)
  • 依赖项传递说明:

    • PUBLIC:使用该选项添加引用,引用的头文件将传染给使用该项目的其他项目。
    • PRIVATE:引用不具备传染性,其他使用该项目的项目可能要再次添加头文件引用。

    除非项目已经将引用的库完全封装,希望后续的使用者不要再直接调用该引用的库时才该用PRIVATE,否则应设置为PUBLIC。

  • 全局项目设置说明:

    上述部分指令如果去除target_前缀和部分参数,可转为对所有项目的设置的指令。

全局配置

以下指令对所有项目都生效

# 设置全局项目的编译选项
add_compile_options(<option>...)

读取配置

反向获取关于项目的一些配置信息

# 获取项目类型(EXECUTABLE|STATIC_LIBRARY)
get_target_property(<outVar> <projectName> TYPE)

文件系统

既然是基于文件的生成系统,自然经常需要和文件系统打交道。

文件处理

# 获取{当前目录|包括子目录}的满足glob通配符的文件路径并将其路径打包在一个变量列表中
file({GLOB | GLOB_RECURSE} <list> <glob>...)
# 获取相对路径
file(RELATIVE_PATH <output> <root-path> <path>)# 创建或覆盖一个文件并写入指定内容
file(WRITE <file> <content>)
# 向指定文件末尾追加内容
file(APPEND <file> <content>)
# 复制文件或文件夹到目标目录
file(COPY <sourceDir> DESTINATION <destinationDir>)
# 复制并修改文件到指定位置。自动替换文件中的环境变量值(@<var>@)并自动移入当前CMakeLists的构建目录。
configure_file(<inputFile> <outputFile>)

路径计算

# 获取路径对应的父目录地址
cmake_path(GET <path-var> PARENT_PATH <out-var>)
# 获取路径对应的文件名
cmake_path(GET <path-var> FILENAME <out-var>)

其他特殊指令

其他一些特殊但常用的指令

# 在vs中将指定文件分类到与文件系统一致的筛选器结构,而不是默认筛选器。
source_group(TREE <fileRootDir> FILES <inputFile>...)
# 在vs中禁用对指定文件的编译
set_property(SOURCE <files> PROPERTY VS_SETTINGS "ExcludedFromBuild=true")

CMakePresets

https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html

“CMakePresets.json”是 CMake 的配置文件,存放在项目的根目录中,用于配置一些 CMake 构建选项。

示例内容如下:

{//CMakePresets所用的版本"version": 6,//定义生成配置。可定义多个,然后在构建指令中指明。"configurePresets": [{//配置名称"name": "default",//所用的生成器,用于将CMake项目转为原生项目"generator": "Visual Studio 17 2022",//生成输出目录(构建目录)"binaryDir": "${sourceDir}/build",//配置CMake缓存变量(一种长期存储的环境变量,存在CMakeCache.txt文件中)"cacheVariables": {//构建中使用的一些构建工具,由cmake语言写成"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"}}]
}

配置完毕后生成时通过添加--preset选项,如cmake --preset=<presetName>指令使用。

使用技巧

  • 仅添加些文件到 CMake 生成的解决方案文件夹中?

    无法直接支持,但可使用add_custom_target指令间接实现:
    https://stackoverflow.com/questions/20251829/is-it-possible-to-add-files-to-a-cmake-generated-solution-folder-in-visual-studi

参考资料

  • CMake 官方教程
  • CMake 官方文档
  • 理解 cmake 中 PRIVATE、PUBLIC、INTERFACE 的含义和用法

相关新闻

  • 完整教程:[百题重刷]前缀和 + Hash 表:缓存思想, 消除重复计算
  • 万能欧几里得板子
  • 【技术美术】双向透射分布函数

最新新闻

  • 医疗AI落地两大硬坎:临床信任断裂与数据合规失焦
  • Adaboost原理深度解析:理解梯度提升家族的基石
  • 股市语言密码:看懂全球资本流动的翻译之道
  • 终极指南:如何为300+车型部署开源驾驶辅助系统openpilot
  • 2026年文旅行业GEO优化公司“全意图”价值评估指南与选型避坑 - GEO优化
  • MPC857T外部总线接口:对齐、仲裁与原子操作实战解析

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号