文章目录
- 前言
- [一、cmake的3大核心:目标、属性 和 API](#一、cmake的3大核心:目标、属性 和 API)
-
- [1. cmake的3大核心(总结表)](#1. cmake的3大核心(总结表))
- [2. 目标的种类](#2. 目标的种类)
-
- [2.1 目标主要分为两个大类:二进制目标 和 伪目标](#2.1 目标主要分为两个大类:二进制目标 和 伪目标)
- [2.2 伪目标的用法](#2.2 伪目标的用法)
- [3. 目标的属性](#3. 目标的属性)
-
- [3.1 属性的种类 及其 作用域](#3.1 属性的种类 及其 作用域)
- [3.2 属性的传递机制](#3.2 属性的传递机制)
- [4. 操作目标属性的核心API](#4. 操作目标属性的核心API)
- 二、重点函数解析
-
- [1. cmake_minimum_required](#1. cmake_minimum_required)
- [2. project](#2. project)
-
- [2.1 project函数的介绍](#2.1 project函数的介绍)
- [2.2 project() 执行后,CMake会自动创建一些变量(project()执行后,才能设置 语言的版本)](#2.2 project() 执行后,CMake会自动创建一些变量(project()执行后,才能设置 语言的版本))
- [3. include](#3. include)
-
- [3.1 include函数的介绍](#3.1 include函数的介绍)
- [3.2 文件路径(< file >) vs 模块名(< module >)](#3.2 文件路径(< file >) vs 模块名(< module >))
- [3.3 父目录CMakeLists.txt文件 include子目录文件后,内置变量的变化情况](#3.3 父目录CMakeLists.txt文件 include子目录文件后,内置变量的变化情况)
- [4. add_subdirectory](#4. add_subdirectory)
-
- [4.1 add_subdirectory函数的介绍](#4.1 add_subdirectory函数的介绍)
- [4.2 父目录CMakeLists.txt文件 add_subdirectory子目录(含CMakeLists.txt)后,内置变量的变化情况](#4.2 父目录CMakeLists.txt文件 add_subdirectory子目录(含CMakeLists.txt)后,内置变量的变化情况)
- [5. add_executable](#5. add_executable)
- [6. add_library](#6. add_library)
- [7. target_include_directories](#7. target_include_directories)
-
- [7.1 target_include_directories函数的介绍](#7.1 target_include_directories函数的介绍)
- [7.2 与 include_directories() 的区别](#7.2 与 include_directories() 的区别)
- [8. target_link_libraries](#8. target_link_libraries)
- [9. set_target_properties](#9. set_target_properties)
- [10. file](#10. file)
-
- [10.1 file函数的介绍](#10.1 file函数的介绍)
- [10.2 文件匹配表达式语法(含示例演示)](#10.2 文件匹配表达式语法(含示例演示))
前言
include函数 与 add_subdirectory函数的对比(学习 变量知识之后补充)
一、cmake的3大核心:目标、属性 和 API
1. cmake的3大核心(总结表)
bash
Target
│
├─ 类型
│ ├─ EXECUTABLE
│ ├─ STATIC / SHARED / MODULE
│ ├─ OBJECT / INTERFACE
│ └─ IMPORTED / ALIAS
│
├─ 属性(≈键值表)
│ ├─ Build impl ─ SOURCES COMPILE_OPTIONS ...
│ ├─ Usage reqs ─ INTERFACE_INCLUDE_DIRECTORIES ...
│ ├─ Output/Install ─ VERSION SOVERSION OUTPUT_NAME ...
│ └─ Meta ─ TYPE ALIASED_TARGET ...
│
├─ API
│ ├─ add_library / add_executable
│ ├─ target_* (compile_options, link_libraries, include_dirs)
│ ├─ set/get_target_properties
│ └─ install(TARGETS) / export
│
└─ 流程:
配置期 → ⽬标注册 + 属性写⼊
⽣成期 → 属性转具化到 Make/Ninja
构建期 → 编译 & 链接
安装期 → 使⽤属性⽣成 cmake_install.cmake
2. 目标的种类
2.1 目标主要分为两个大类:二进制目标 和 伪目标
- 二进制目标(Binary Targets)
| 类型 | 创建命令 | 产物例子 / 说明 |
|---|---|---|
| 可执行文件(Executable) | add_executable(targetName sources...) | 生成可直接运行的程序(如my_app.exe或my_tool) |
| 静态库(Static Library) | add_library(targetName STATIC sources...) | 生成.a(Linux)或.lib(Windows)文件,代码在编译时直接嵌入可执行文件 |
| 共享库(Shared Library) | add_library(targetName SHARED sources...) | 生成.so(Linux)或.dll(Windows)文件,运行时动态加载 |
| 模块库(Module Library) | add_library(targetName MODULE sources...) | 类似共享库,但不作为依赖链接(不在target_link_libraries()右侧使用),通常作为插件动态加载(如dlopen) |
| 对象库(Object Library) | add_library(targetName OBJECT sources...) | 编译源文件生成目标文件(.o/.obj),不归档或链接 |
- 伪目标(Pseudo Targets): 不生成实际文件,用于构建系统逻辑组织
| 类型 | 创建命令 | 作用 |
|---|---|---|
| 导入目标(Imported Target) | add_library(targetName [SHARED/STATIC] IMPORTED) | 引用外部已存在的库(如第三方库) |
| 别名目标(Alias Target) | add_library(aliasName ALIAS targetName) | (1)作用: 为目标创建 只读别名 ,简化跨目录引用(如统一接口名) (2)限制: 别名目标 不能被安装或导出 |
| 接口库(Interface Library) | add_library(targetName INTERFACE) | 传递编译属性(如头文件路径、宏定义),不生成二进制文件 |
2.2 伪目标的用法
伪目标(Pseudo Targets):不生成实际文件,用于构建系统逻辑组织
- 导入目标 (Imported Target)
(1) 核心作用:
引用外部已存在的库文件(如系统库或预编译的第三方库)
(2) 关键特性:
不参与构建过程
提供统一的接口链接外部库
可传递编译属性(头文件路径、链接选项等)
(3) 创建与配置:
bash
# 基本声明
add_library(boost_system SHARED IMPORTED)
set_target_properties(boost_system PROPERTIES
# 设置库文件路径
IMPORTED_LOCATION /usr/lib/libboost_system.so
# 设置头文件路径(自动传递给链接者)
INTERFACE_INCLUDE_DIRECTORIES /usr/include/boost
# 添加宏定义
INTERFACE_COMPILE_DEFINITIONS BOOST_SYSTEM_DYN_LINK
)
IMPORTED_LOCATION 是一个导入目标(IMPORTED target)的属性,它用于指定 导入目标 对应的库文件在磁盘上的位置。这个属性是导入目标所特有的,并且它不会自动传播给依赖者。
IMPORTED_LOCATION 属性必须使用 绝对路径 指定导入目标对应的文件位置。
使用示例:
bash
# 主项目中链接导入目标
add_executable(network_app main.cpp)
target_link_libraries(network_app PRIVATE boost_system)
# 使用效果:
# (1)编译时:
# 1. 自动添加头文件搜索路径:-I/usr/include/boost
# 2. 自动添加宏定义:-DBOOST_SYSTEM_DYN_LINK
# (2)链接时:
# 1. 链接 库的绝对路径:/usr/lib/libboost_system.so
- 别名目标 (Alias Target)
(1) 核心作用:
为目标创建不可修改的别名(只读引用)
(2) 关键特性:
简化复杂目标名的引用
统一接口(如提供命名空间)
不能安装或导出
(3) 创建方法:
bash
# 原始库目标
add_library(complex_math_static STATIC complex.cpp)
# 创建别名(带命名空间)
add_library(math::complex ALIAS complex_math_static)
使用示例:
bash
# 跨CMakeLists.txt统一使用别名
# 原始文件:src/CMakeLists.txt
add_library(encryption STATIC aes.cpp)
add_library(crypto::encryption ALIAS encryption)
# 其他文件:app/CMakeLists.txt
add_executable(secure_chat chat.cpp)
target_link_libraries(secure_chat PRIVATE
math::complex # 来自不同目录的库
crypto::encryption # 通过别名统一接口
)
# 优势:
# 1. 避免目标名冲突
# 2. 代码可读性强
# 3. 解耦具体实现
- 接口库 (Interface Library)
(1) 核心作用:
传递编译属性,不生成任何二进制文件
(2) 关键特性:
纯属性容器(头文件路径、宏定义、编译选项)
通过 INTERFACE 关键字设置传递属性
适用于头文件库和依赖聚合
(3) 典型应用场景
- 场景1:头文件库(Header-only)
bash
# 创建接口库
add_library(eigen INTERFACE)
# 设置头文件路径(自动传递给链接者)
target_include_directories(eigen INTERFACE
/usr/include/eigen3
${PROJECT_SOURCE_DIR}/external/eigen
)
# 添加宏定义
target_compile_definitions(eigen INTERFACE
EIGEN_NO_DEBUG
EIGEN_USE_BLAS
)
# 使用
add_executable(matrix_demo demo.cpp)
target_link_libraries(matrix_demo PRIVATE eigen) # 传递头文件和宏
- 场景2:依赖聚合(Dependency Aggregation)
bash
# 创建聚合接口库
add_library(logging_dependencies INTERFACE)
# 聚合多个库的依赖
target_link_libraries(logging_dependencies INTERFACE
spdlog::spdlog # 日志库
fmt::fmt # 格式化库
Boost::date_time # 日期处理
)
# 使用
add_library(network_service network.cpp)
target_link_libraries(network_service PRIVATE
logging_dependencies # 单行链接所有日志相关依赖
)
3. 目标的属性
3.1 属性的种类 及其 作用域
| 类别 | 作用域 | 典型场景 |
|---|---|---|
| 目标属性 (Target) | 单个构建目标(库、可执行、接口库...) | 控制库/可执行文件的输出行为 |
| 目录属性 (Directory) | 当前源码目录 及其 子目录 | 统一目录下的编译标准 |
| 全局属性 (Global) | 整个项目 | 跨模块文件收集 |
| 缓存属性 (Cache) | 跨 CMake 运行(持久化) | 用户配置选项 |
| 源文件属性 (Source) | 单个文件 | 文件级编译定制 |
| 测试属性 (Test) | 由 add_test() 创建的单个测试用例 | 测试环境配置 |
| 安装属性(Install) | 由install() 生成的安装清单条目 | 安装路径的配置 |
(1) 目标属性(Target Properties)
-
作用域:绑定到特定构建目标(可执行文件、库)
-
典型属性:
- ARCHIVE_OUTPUT_DIRECTORY
控制静态库(.a/.lib)的输出路径:
bash
set_target_properties(MyLib PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "lib/static")
- LIBRARY_OUTPUT_DIRECTORY
控制动态库(.so/.dll)的输出路径:
bash
set_target_properties(MyLib PROPERTIES LIBRARY_OUTPUT_DIRECTORY "lib/shared")
- 目标属性的传递机制:
通过 PRIVATE/PUBLIC/INTERFACE 控制依赖传播:
bash
target_include_directories(MyLib PUBLIC include) # 头文件路径传递给依赖者
(2) 目录属性(Directory Properties)
-
作用域:当前目录及子目录
-
典型属性:
- INCLUDE_DIRECTORIES
目录级头文件搜索路径:
bash
set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES "include/")
- CMAKE_CXX_STANDARD
设置目录内的 C++ 标准:
bash
set_property(DIRECTORY PROPERTY CMAKE_CXX_STANDARD 17)
(3) 全局属性(Global Properties)
-
作用域:整个项目
-
典型属性:
- ALL_SOURCE_FILES
收集全项目源文件(跨模块共享):
bash
set_property(GLOBAL PROPERTY ALL_SOURCE_FILES "") # 初始化
set_property(GLOBAL PROPERTY ALL_SOURCE_FILES APPEND src/main.cpp) # 追加文件
- COMPILE_OPTIONS
全局编译选项(慎用,可能污染):
bash
set_property(GLOBAL PROPERTY COMPILE_OPTIONS "-Wall")
(4) 缓存变量属性(Cache Properties)
-
作用域: 持久化存储(跨 CMake 运行)
-
典型属性:
- STRINGS
限制缓存变量的可选值:
bash
set(CRYPTOBACKEND "OpenSSL" CACHE STRING "Backend selector")
set_property(CACHE CRYPTOBACKEND PROPERTY STRINGS "OpenSSL" "LibTomCrypt") # 下拉菜单选项
(5) 源文件属性(Source File Properties)
-
作用域:单个源文件(.cpp/.h)
-
典型属性:
- COMPILE_DEFINITIONS
文件级宏定义:
bash
set_property(SOURCE src.cpp PROPERTY COMPILE_DEFINITIONS "USE_DEBUG=1")
- COMPILE_FLAGS
文件级编译选项:
bash
set_property(SOURCE legacy.cpp PROPERTY COMPILE_FLAGS "-Wno-deprecated")
(6) 测试属性(Test Properties)
-
作用域:由 add_test() 创建的单个测试用例
-
典型属性:
bash
add_test(NAME BatteryTest
COMMAND battery_tester
)
# 设置测试属性
set_tests_properties(BatteryTest PROPERTIES
ENVIRONMENT "TEMP_DIR=/tmp;LOG_LEVEL=debug" # 环境变量
TIMEOUT 120 # 超时时间(秒)
LABELS "hardware;critical" # 测试分类标签
COST 1.5 # 资源消耗权重
)
(7) 安装属性(Install Properties)
-
作用域:由install() 生成的安装清单条目
-
典型属性:
- 目标安装属性(Target Install Properties)
绑定到具体目标(可执行文件/库):
bash
# 设置目标安装路径和组件
set_target_properties(MyApp PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
INSTALL_RPATH "$ORIGIN/../lib" # 安装后库搜索路径
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/static"
)
# 安装目标时应用属性
install(TARGETS MyApp
RUNTIME DESTINATION bin COMPONENT Runtime
LIBRARY DESTINATION lib COMPONENT Development
)
- 文件安装属性(File Install Properties)
bash
# 设置文件权限和组件
install(FILES "config.ini"
DESTINATION etc
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ
COMPONENT Config
)
- 目录安装属性(Directory Install Properties)
bash
# 目录安装控制
install(DIRECTORY docs/
DESTINATION share/doc
FILE_PERMISSIONS OWNER_READ
DIRECTORY_PERMISSIONS OWNER_READ OWNER_EXECUTE
)
3.2 属性的传递机制
| 关键字 | 对当前目标的影响 | 是否传播 | 对当前目标依赖者的影响 | 解释 |
|---|---|---|---|---|
| PRIVATE | ✅ 生效 | ❌ 否 | ❌ 不生效 | 只自己用 |
| PUBLIC | ✅ 生效 | ✅ 是 | ✅ 生效 | 自己-依赖者用 |
| INTERFACE | ❌ 不生效 | ✅ 是 | ✅ 生效 | 自己不用-依赖者用 |
4. 操作目标属性的核心API
| 类别 | 典型命令(可选关键词) | 主要作用 | 涉及的核心属性(部分示例) |
|---|---|---|---|
| 通用读 / 写接口 | set_target_properties() get_target_property() | 任意目标属性的设置、追加、查询(最底层API) | 任何 prop_tgt |
| 编译阶段相关 | target_compile_definitions target_compile_options target_precompile_headers target_include_directories target_sources | 控制源文件编译:宏定义、编译选项 、语言特性、预编译头、包含目录、源文件列表等 | COMPILE_DEFINITIONS(预处理器宏定义) COMPILE_OPTIONS(编译器选项) COMPILE_FEATURES PRECOMPILE_HEADERS INCLUDE_DIRECTORIES(指定头文件搜索路径) SOURCES 等 |
| 链接 & 输出阶段相关 | target_link_libraries target_link_options target_link_directories | 配置目标被链接时的库、选项及搜索路径 | LINK_LIBRARIES(目标直接链接的库列表) INTERFACE_LINK_LIBRARIES(目标传递给依赖者的库列表) LINK_OPTIONS(设置目标专用的链接器) INTERFACE_LINK_OPTIONS(传递链接器选项给依赖目标) LINK_DIRECTORIES(目标链接时的库搜索路径) INTERFACE_LINK_DIRECTORIES(传递库搜索路径给依赖目标) |
| 安装 & 打包阶段相关 | install(TARGETS ...) install(EXPORT ...) | 生成安装规则与包,控制目标在安装树中的 布局 及其 运行时行为 | RUNTIME_OUTPUT_DIRECTORY(可执行文件的输出路径) LIBRARY_OUTPUT_DIRECTORY(动态库的输出路径) ARCHIVE_OUTPUT_DIRECTORY(静态库的输出路径) EXPORT_NAME INSTALL_RPATH |
二、重点函数解析
1. cmake_minimum_required
- 函数作用:
指定项目所需的最低 CMake 版本,应该放在顶级 CMakeLists.txt 的第一行。
- 函数形式:
c
cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])
- 参数解析:
| 参数 | 含义 | 示例 |
|---|---|---|
| VERSION | 关键字,表示后面跟的是版本号 | |
| < min > | 必需参数,指定最低 CMake 版本(格式:major.minor[.patch],如 3.10.2) | VERSION 3.5 |
| < policy_max > | 可选参数(CMake ≥3.12 支持),指定策略兼容的最高版本,需 ≥ < min > | VERSION 3.10...3.15 |
| FATAL_ERROR(可选) | 历史遗留参数(CMake ≤2.4 需显式指定),现代版本中可忽略。 若指定,当 CMake 版本不满足时会终止配置并报错(CMake 2.6+ 默认为此行为,所以不用显式指定) | VERSION 3.5 FATAL_ERROR |
- 举例说明:
(1) 示例一:
bash
cmake_minimum_required(VERSION 3.10) # 要求 CMake ≥3.10
若系统 CMake 为 3.9,则输出:
bash
CMake Error: CMake 3.10 or higher is required. You are running version 3.9
(2) 示例二:
bash
cmake_minimum_required(VERSION 3.10...3.15) # 要求 CMake 版本在 3.10 至 3.15 之间
版本检查:
若当前 CMake 版本 低于 < min >(此处是3.10),直接报错终止构建。
若当前版本 高于 < policy_max >(此处是3.15),仍可构建,但策略行为按 < policy_max >(3.15) 生效。

2. project
2.1 project函数的介绍
- 函数作用:
指定 全局唯一项目名称 ( 后续通过 ${PROJECT_NAME} 引用 )
该函数 放在顶级CMakeLists文件的第二行,子目录的CMakeLists文件 中一般无需调用。
大多数项目都只有⼀个名字,复杂项目如c++的boost 库,每一个子功能都设置一个project
- 基本形式:
bash
project(<PROJECT-NAME>)
- 完整形式
bash
project(<PROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[DESCRIPTION <project-description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])
- 参数解析:
| 参数 | 作用 |
|---|---|
| < PROJECT-NAME > | 项目名称(如 MyProject),用于生成默认变量(如 PROJECT_NAME) |
| VERSION(可选) | 项目版本号(如 1.0.0),会自动定义 PROJECT_VERSION 等变量 |
| DESCRIPTION(可选) | 项目描述信息(用于生成文档或包配置) |
| HOMEPAGE_URL(可选) | 项目主页 URL |
| LANGUAGES(可选) | 指定项目支持的语言(如 C、CXX、Fortran、ASM 等) |
- 举例说明:
(1) 示例一:
bash
project(MyBackendService) # 定义项目名称为"MyBackendService"
创建全局唯一项目名称 "MyBackendService"(后续通过 ${PROJECT_NAME} 引用)
如未使用 LANGUAGES 显式指定项目支持的语言:
会自动激活 C 和 CXX(C++)语言支持, 触发编译器探测(默认查找 gcc/g++ 或 clang/clang++)
(2) 示例二:
bash
project(MyBackendService
VERSION 1.4.0 # 版本管理
DESCRIPTION "High-performance TCP server"
HOMEPAGE_URL "https://github.com/your/repo"
LANGUAGES CXX # 显式指定 C++(重要!)
)
如果编写C++代码,强烈建议指定 LANGUAGES CXX,只使用C++语言支持(禁用C语言),避免C/C++混合编译的符号冲突
2.2 project() 执行后,CMake会自动创建一些变量(project()执行后,才能设置 语言的版本)
| 变量 | 描述 |
|---|---|
| PROJECT_NAME | 项目名称(如 MyProject) |
| CMAKE_PROJECT_NAME | 顶级项目名称(与 PROJECT_NAME 相同) |
| PROJECT_SOURCE_DIR | 顶级 CMakeLists.txt 所在目录(即源文件树根目录) |
| PROJECT_BINARY_DIR | 构建目录(如 build/) |
| PROJECT_VERSION | 完整版本号(如 1.2.3) |
| PROJECT_VERSION_MAJOR | 主版本号(如 1) |
| PROJECT_VERSION_MINOR | 次版本号(如 2) |
| PROJECT_VERSION_PATCH | 修订号(如 3) |
- 在 project() 选择了项目支持的语言之后,还能紧接着设置 语言的版本:
bash
project(MyService
LANGUAGES CXX
)
set(CMAKE_CXX_STANDARD 20) # 启用 C++20
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 强制要求
| 配置组合 | 行为描述 |
|---|---|
| CMAKE_CXX_STANDARD=20 REQUIRED=OFF(默认) | 尝试使用 C++20,若编译器不支持(如仅支持 C++17),则自动回退到编译器支持的最高版本,仅输出警告。 |
| CMAKE_CXX_STANDARD=20 REQUIRED=ON(强制要求) | 严格检查编译器对 C++20 的支持,若不满足则立即报错,停止构建。 |
3. include
3.1 include函数的介绍
- 函数作用:
加载并执行指定文件(.cmake)或 模块中的 CMake 代码,被包含的代码会立即在 当前作用域 执行,如同直接粘贴到 include 位置。
作用域特性:
默认全局生效,被包含文件中定义的变量、函数、宏会覆盖当前作用域的同名对象
- 函数形式:
bash
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>] [NO_POLICY_SCOPE])
- 参数解析:
| 参数 | 作用 | 示例 |
|---|---|---|
| OPTIONAL(可选) | 文件不存在时不报错,静默跳过(否则会触发 FATAL_ERROR) | include(legacy.cmake OPTIONAL) |
| RESULT_VARIABLE(可选) | 将查找结果存入变量:成功时为文件绝对路径,失败时为 NOTFOUND | cmake include(config.cmake RESULT_VARIABLE found) if(NOT found) message(WARNING "未找到配置文件") endif() |
| NO_POLICY_SCOPE(可选) | 阻止被包含文件中的策略设置(如 cmake_policy)影响当前作用域 | cmake include(policy.cmake NO_POLICY_SCOPE) |
3.2 文件路径(< file >) vs 模块名(< module >)
| 类型 | 定义 | 搜索规则 |
|---|---|---|
| 文件路径 | 直接指向 .cmake 脚本的绝对路径 或 相对路径(如 cmake/config.cmake) | (1)如果是绝对路径,直接从对应路径加载 (2)如果指定的是相对路径,则相对当前的正在执行的CMakeLists.txt 所在的目录 |
| 模块名 | 代表 用户自定义 或 CMake 内置的模块名(如 FindOpenSSL) | 1. 在 CMAKE_MODULE_PATH 中查找 <模块名>.cmake 2. 在 CMake 安装目录的 Modules/ 下查找内置模块 |
关键区别:
文件路径需显式指定文件扩展名(通常为 .cmake),而模块名无需扩展名,CMake 自动补全
- 文件路径:绝对路径 和 相对路径
- 相对路径
解析规则:相对于 当前处理的 CMakeLists.txt 所在目录(CMAKE_CURRENT_LIST_DIR)。
bash
# 假设目录结构:
# project/
# ├── CMakeLists.txt
# └── cmake/
# └── config.cmake
include(cmake/config.cmake) # ✅ 正确:相对当前 CMakeLists.txt
- 绝对路径
解析规则:直接使用完整路径,不依赖上下文。
bash
include(/home/user/project/cmake/config.cmake) # ✅ 明确指定位置
include(${PROJECT_SOURCE_DIR}/cmake/helpers.cmake) # ✅ 通过变量动态构建绝对路径
- 模块名:模块路径的定制(修改 CMAKE_MODULE_PATH)
- 在 CMAKE_MODULE_PATH 中查找用户自定义的 <模块名>.cmake
bash
# 项目结构:
# project/
# ├── CMakeLists.txt
# └── cmake/
# ├── modules/
# │ └── FindMyLib.cmake
# └── ProjectOptions.cmake
# 根 CMakeLists.txt
list(APPEND CMAKE_MODULE_PATH
${CMAKE_CURRENT_LIST_DIR}/cmake # 添加 cmake 目录,这样可以直接 include(ProjectOptions)
${CMAKE_CURRENT_LIST_DIR}/cmake/modules # 添加 modules 目录,这样可以直接 include(FindMyLib)
)
include(ProjectOptions) # 从 cmake/ 目录查找 ProjectOptions.cmake
include(FindMyLib) # 从 cmake/modules/ 目录查找 FindMyLib.cmake
- 使用内置模块
bash
include(CheckCXXCompilerFlag) # ✅ 模块名:查找 CMake 内置的 CheckCXXCompilerFlag.cmake
cmake的更多内置模块,咨询AI
3.3 父目录CMakeLists.txt文件 include子目录文件后,内置变量的变化情况
- 4个描述位置 的cmake内置变量说明:
| 变量名 | 含义 |
|---|---|
| CMAKE_CURRENT_SOURCE_DIR | 表示当前正在处理的CMakeLists.txt文件所在的源目录路径 |
| CMAKE_CURRENT_BINARY_DIR | 表示当前正在处理的CMakeLists.txt对应的构建目录路径 |
| CMAKE_CURRENT_LIST_FILE | 表示当前正在处理的列表文件(CMakeLists.txt 或 .cmake文件)的完整路径 |
| CMAKE_CURRENT_LIST_DIR | 表示当前正在处理的列表文件(CMakeLists.txt 或 .cmake文件)所在的目录路径 |
bash
# 项目结构
project/ # 源目录:/home/user/project (假设的源文件目录绝对路径)
├── CMakeLists.txt # 父级文件
├── build/ # 构建目录(在project下创建)
└── sub/ # 子目录
├── sub.cmake # 自定义脚本
└── CMakeLists.txt # 子构建文件
- 父目录CMakeLists.txt文件 include子目录文件后,内置变量的变化情况:
bash
# 父级 CMakeLists.txt 内容( project/CMakeLists.txt )
cmake_minimum_required(VERSION 3.10)
project(ParentProject)
message("【父级】SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message("【父级】BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
message("【父级】LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message("【父级】LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
include(sub/sub.cmake) # 包含子目录的 .cmake 文件
include(sub/CMakeLists.txt) # 包含子目录的 CMakeLists.txt
(1) 场景一:include(sub/sub.cmake) 时的变量变化
bash
# sub/sub.cmake 文件内容
message(">> 【sub.cmake】SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message(">> 【sub.cmake】BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
message(">> 【sub.cmake】LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message(">> 【sub.cmake】LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
输出结果(与父级 CMakeLists.txt 的输出结果对比):
bash
【父级】SOURCE_DIR: /home/user/project
【父级】BINARY_DIR: /home/user/project/build
【父级】LIST_FILE: /home/user/project/CMakeLists.txt
【父级】LIST_DIR: /home/user/project
>> 【sub.cmake】SOURCE_DIR: /home/user/project # 不变
>> 【sub.cmake】BINARY_DIR: /home/user/project/build # 不变
>> 【sub.cmake】LIST_FILE: /home/user/project/sub/sub.cmake # 更新为当前文件
>> 【sub.cmake】LIST_DIR: /home/user/project/sub # 更新为当前目录
(2) 场景二:include(sub/CMakeLists.txt) 时的变量变化
bash
# sub/CMakeLists.txt
message(" [子CMake] SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message(" [子CMake] BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
message(" [子CMake] LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message(" [子CMake] LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
输出结果(与父级 CMakeLists.txt 的输出结果对比):
bash
>> [子CMake] SOURCE_DIR: /home/user/project # 不变
>> [子CMake] BINARY_DIR: /home/user/project/build # 不变
>> [子CMake] LIST_FILE: /home/user/project/sub/CMakeLists.txt # 更新为当前文件
>> [子CMake] LIST_DIR: /home/user/project/sub # 更新为当前目录
| 变量名 | 进入子目录后是否变化? | 说明 |
|---|---|---|
| CMAKE_CURRENT_SOURCE_DIR | 不变化 | 还是父目录的源代码树的目录 |
| CMAKE_CURRENT_BINARY_DIR | 不变化 | 还是父目录的构建树的目录 |
| CMAKE_CURRENT_LIST_FILE | ✅ 变化 | 变为子目录的 CMakeLists.txt 或 .cmake文件 的文件全路径 |
| CMAKE_CURRENT_LIST_DIR | ✅ 变化 | 变为子目录的 CMakeLists.txt 或 .cmake文件 的文件目录 |
- 终极总结:
(1)include() 本质是代码插入:
不改变构建上下文 ,所有路径操作仍在 父级作用域 进行
SOURCE_DIR / BINARY_DIR 始终指向父级上下文,即使包含的是子目录的 CMakeLists.txt
(2)四个变量的黄金法则:
SOURCE_DIR / BINARY_DIR: 构建作用域的位置
LIST_FILE / LIST_DIR: 当前文件的物理位置
4. add_subdirectory
4.1 add_subdirectory函数的介绍
- 函数作用:
递归执行子目录的 CMakeLists.txt,实现多层级项目管理
子目录的CMakeLists.txt文件中 定义的目标(库/可执行文件)在父目录中自动可见,可直接链接
- 函数形式:
bash
add_subdirectory(source_dir
[binary_dir]
[EXCLUDE_FROM_ALL]
)
- 参数解析:
| 参数 | 作用 | 示例 |
|---|---|---|
| source_dir | 必需包含 子目录路径(相对当前 CMakeLists.txt 所处目录 或 绝对路径),需包含 CMakeLists.txt 文件 | add_subdirectory(lib) |
| binary_dir | 可选。指定子目录的构建输出路径(默认与 source_dir 同名) | add_subdirectory(lib build/lib) → 输出到 build/lib 目录 |
| EXCLUDE_FROM_ALL(不重要) | 可选。排除子目录目标从默认构建(make all)。若父目标依赖子目标,仍会构建 | add_subdirectory(tests EXCLUDE_FROM_ALL) → 需手动构建测试目标 |
- 举例说明:
bash
# 项目结构
project/
├── CMakeLists.txt
├── app.cpp
└── mylib/
├── CMakeLists.txt # add_library(mylib ...)
└── mylib.cpp
# 父目录 CMakeLists.txt
add_subdirectory(mylib) # 引入子目录
add_executable(myapp app.cpp)
target_link_libraries(myapp PRIVATE mylib) # 链接子目录库
4.2 父目录CMakeLists.txt文件 add_subdirectory子目录(含CMakeLists.txt)后,内置变量的变化情况
- 4个描述位置 的cmake内置变量说明:
| 变量名 | 含义 |
|---|---|
| CMAKE_CURRENT_SOURCE_DIR | 表示当前正在处理的CMakeLists.txt文件所在的源目录路径 |
| CMAKE_CURRENT_BINARY_DIR | 表示当前正在处理的CMakeLists.txt对应的构建目录路径 |
| CMAKE_CURRENT_LIST_FILE | 表示当前正在处理的列表文件(CMakeLists.txt 或 .cmake文件)的完整路径 |
| CMAKE_CURRENT_LIST_DIR | 表示当前正在处理的列表文件(CMakeLists.txt 或 .cmake文件)所在的目录路径 |
- 假设我们有以下项目结构:
bash
# 项目结构
/root-project/
├── CMakeLists.txt # 父目录的CMakeLists.txt
├── build/ # 构建目录(我们在此执行cmake命令)
└── lib/
└── CMakeLists.txt # 子目录的CMakeLists.txt
父目录的CMakeLists.txt(/root-project/CMakeLists.txt):
bash
cmake_minimum_required(VERSION 3.10)
project(RootProject)
message("\n=== 父目录 (开始) ===")
message("CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message("CMAKE_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
message("CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message("CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
# 添加子目录
add_subdirectory(lib)
message("\n=== 父目录 (子目录处理后) ===")
message("CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message("CMAKE_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
message("CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message("CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
子目录的CMakeLists.txt(/root-project/lib/CMakeLists.txt):
bash
message("\n=== 子目录 ===")
message("CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message("CMAKE_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
message("CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message("CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
- 输出结果(从 /root-project/build 目录执行 cmake ...):
bash
=== 父目录 (开始) ===
CMAKE_CURRENT_SOURCE_DIR: /root-project
CMAKE_CURRENT_BINARY_DIR: /root-project/build
CMAKE_CURRENT_LIST_FILE: /root-project/CMakeLists.txt
CMAKE_CURRENT_LIST_DIR: /root-project
=== 子目录 ===
CMAKE_CURRENT_SOURCE_DIR: /root-project/lib # 切换到子目录源代码路径
CMAKE_CURRENT_BINARY_DIR: /root-project/build/lib # 切换到子目录构建路径
CMAKE_CURRENT_LIST_FILE: /root-project/lib/CMakeLists.txt # 切换到当前正在处理的CMakeLists.txt文件 的路径
CMAKE_CURRENT_LIST_DIR: /root-project/lib # 切换到当前正在处理的CMakeLists.txt文件 的目录
=== 父目录 (子目录处理后) ===
CMAKE_CURRENT_SOURCE_DIR: /root-project
CMAKE_CURRENT_BINARY_DIR: /root-project/build
CMAKE_CURRENT_LIST_FILE: /root-project/CMakeLists.txt
CMAKE_CURRENT_LIST_DIR: /root-project
| 变量名 | 进入子目录后是否变化? | 说明 |
|---|---|---|
| CMAKE_CURRENT_SOURCE_DIR | ✅ 变化 | 切换到子目录源代码路径 |
| CMAKE_CURRENT_BINARY_DIR | ✅ 变化 | 切换到子目录构建路径 |
| CMAKE_CURRENT_LIST_FILE | ✅ 变化 | 变为子目录的 CMakeLists.txt 文件 的文件全路径 |
| CMAKE_CURRENT_LIST_DIR | ✅ 变化 | 变为子目录的 CMakeLists.txt 文件 的文件目录 |
- 关键点总结
(1) 作用域绑定:这些变量始终与当前正在处理的 CMakeLists.txt 文件相关联
(2) 作用域切换:当 add_subdirectory() 被调用时:
- 构建上下文切换到子目录
- 所有四个变量更新为子目录的值
- 子目录处理完毕后,上下文返回到父目录
- 所有变量恢复为父目录的值
5. add_executable
- 函数作用:
指示 cmake 从源代码生成一个可执行文件
- 函数形式:
bash
add_executable(<target_name>
[source1] [source2 ...]
)
- 参数解析:
| 参数 | 作用 |
|---|---|
| target_name | 可执行文件的名称(不包含扩展名,如 myapp),项目内部唯一 |
| [source ...] | 源文件列表(如 src/main.cpp) |
- 举例说明:
(1) 示例一(生成 可执行文件):
通过源文件构建可执行目标:
bash
add_executable(my_app main.cpp utils.cpp)
可用 file(GLOB) 收集源文件:
bash
file(GLOB APP_SOURCES "src/*.cpp") # 收集 src 目录下所有 .cpp 文件
add_executable(app ${APP_SOURCES})
默认情况下,将在与调用命令的CMakeLists.txt的目录相对应的 build tree directory 中创建可执行文件。 可以通过 RUNTIME_OUTPUT_DIRECTORY 目标属性,去更改可执行文件的 默认输出位置
(2) 示例二(导入 可执行文件):
引用外部预编译的可执行文件(如系统工具):
bash
add_executable(git_tool IMPORTED)
set_property(TARGET git_tool PROPERTY
IMPORTED_LOCATION "/usr/bin/git"
)
(3) 示例三(为可执行文件 创建别名):
为现有目标(可执行文件)创建 别名(只读引用):
bash
add_executable(app_alias ALIAS my_app) # 为 my_app 创建别名
不能通过别名 修改原目标属性(如 target_link_libraries)
别名不能 被安装或导出
6. add_library
- 函数作用:
CMake 中定义库目标的核心命令,支持创建多种类型的库
- 函数形式:
bash
add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [<source>...])
- 参数解析:
| 参数 | 作用 | 规则与示例 |
|---|---|---|
| < name > | 必需,指定库的名称(不包含前缀和后缀,如 Foo 会生成 libFoo.a)。项目中必须全局唯一 | |
| STATIC / SHARED / MODULE | 可选,指定库类型(不显示指定时,会使用默认值。默认由 BUILD_SHARED_LIBS 决定) | - STATIC:静态库(.a/.lib) - SHARED:动态库(.so/.dll) - MODULE:插件库(运行时动态加载) |
| EXCLUDE_FROM_ALL(不重要,很少用) | 可选,目标不参与默认构建(如 make all) | |
| < source >... | 源文件列表 | 支持通配符(file(GLOB))和 生成器表达式($<...>) |
- 举例说明:
(1) 静态库(STATIC)
bash
add_library(mylib STATIC src/file1.cpp src/file2.cpp)
(2) 共享库(SHARED)
bash
add_library(mylib SHARED src/file1.cpp)
(3) 模块库(MODULE):类似共享库,但不直接链接,需通过 dlopen() 动态加载
bash
add_library(mymodule MODULE src/plugin.cpp)
(4) 对象库(OBJECT):仅编译源文件为 .o/.obj,不归档或链接,供其他目标复用
bash
add_library(myobj OBJECT src/utils.cpp)
add_executable(app $<TARGET_OBJECTS:myobj> src/main.cpp) # 复用对象文件
(5) 接口库(INTERFACE):不生成实际文件。仅传递头文件路径/编译定义等依赖
bash
add_library(myheader INTERFACE)
# 其他目标链接此库自动继承头文件路径
target_include_directories(myheader INTERFACE include/)
target_link_libraries(app PRIVATE myheader)
(6) 导入库(IMPORTED):不生成实际文件。引用外部预编译库
bash
add_library(openssl SHARED IMPORTED)
set_target_properties(openssl PROPERTIES
IMPORTED_LOCATION "/usr/lib/libssl.so"
INTERFACE_INCLUDE_DIRECTORIES "/usr/include/openssl"
)
(7) 别名库(ALIAS):不生成实际文件。为目标创建只读别名(简化引用,不修改原目标)
bash
add_library(mylib::alias ALIAS mylib) # 通过别名链接
target_link_libraries(app PRIVATE mylib::alias)
7. target_include_directories
7.1 target_include_directories函数的介绍
- 函数作用:
用于为特定目标(如库或可执行文件)添加头文件搜索路径的核心命令
- 函数形式:
bash
target_include_directories(<target>
[SYSTEM]
[BEFORE]
<INTERFACE|PUBLIC|PRIVATE> path1 [path2 ...]
[<INTERFACE|PUBLIC|PRIVATE> pathN ...] ...
)
- 参数解析:
| 参数 | 作用 | 说明 |
|---|---|---|
| < target > | 指定需添加头文件路径的 目标(如 my_lib 或 my_app) | 必须是通过 add_executable() 或 add_library() 创建的目标,不能是别名目标(ALIAS target) |
| SYSTEM(不重要,很少用) | 可选,系统头文件标记 | |
| BEFORE(不重要,很少用) | 可选,将路径插入到已有列表最前面 | |
| INTERFACE / PUBLIC / PRIVATE | 属性的作用域关键字 | |
| path1 [path2 ...] | 指定头文件路径 | (1)绝对路径 (2)相对路径:相对于 CMAKE_CURRENT_SOURCE_DIR |
- 举例说明:
bash
# 数学库项目
add_library(math STATIC src/vector.cpp src/matrix.cpp)
# 公开头文件目录(依赖此库的目标自动继承)
target_include_directories(math
PUBLIC include/math # API头文件:用户需包含 <math/vector.h>
)
# 私有头文件目录(仅内部实现使用)
target_include_directories(math
PRIVATE src/internal # 内部头文件:如 _impl_helpers.h
)
7.2 与 include_directories() 的区别
| 函数 | 作用范围 | 推荐度 |
|---|---|---|
| include_directories() | 全局(当前及子目录所有目标) | 低(易造成路径污染) |
| target_include_directories() | 目标级(精确控制) | 高(现代 CMake 最佳实践) |
8. target_link_libraries
- 函数作用:
管理目标依赖关系的核心命令,通过作用域关键字精确控制依赖的传递性
一般用来:设置二进制目标的依赖库列表,相当于使用通用的set属性设置函数设置了LINK_LIBRARIES 或者 INTERFACE_LINK_LIBRARIES这个属性
- 函数形式:
bash
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...
)
- 参数解析:
| 参数 | 作用 | 说明 |
|---|---|---|
| < target > | 指定 目标名称(如 my_lib 或 my_app) | 必须是通过 add_executable() 或 add_library() 创建的目标,不能是别名目标(ALIAS target) |
| INTERFACE / PUBLIC / PRIVATE | 属性的作用域关键字 | |
| < item >... | 依赖库列表 |
- 举例说明:
(1) 可执行文件目标 依赖动/静态库
bash
# 静态库
add_library(voltage_sensor STATIC
src/sensor/adc.cpp
src/sensor/calibration.cpp
)
target_include_directories(voltage_sensor PUBLIC include/sensor)
# 可执行文件
add_executable(bms_monitor
main.cpp
src/core/processor.cpp
)
target_link_libraries(bms_monitor PRIVATE voltage_sensor) # 链接静态库
bash
# 动态库
add_library(balancing_algo SHARED
src/algorithms/neighbor.cpp
src/algorithms/fuzzy_logic.cpp
)
set_target_properties(balancing_algo PROPERTIES
VERSION 1.2
SOVERSION 1
)
# 可执行文件
add_executable(balancer_ctl controller.cpp)
target_link_libraries(balancer_ctl PRIVATE balancing_algo) # 链接动态库
(2) 目标依赖接口库
bash
# 创建接口库
add_library(eigen INTERFACE)
# 设置头文件路径(自动传递给链接者)
target_include_directories(eigen INTERFACE
/usr/include/eigen3
${PROJECT_SOURCE_DIR}/external/eigen
)
# 添加宏定义
target_compile_definitions(eigen INTERFACE
EIGEN_NO_DEBUG
EIGEN_USE_BLAS
)
# 使用
add_executable(matrix_demo demo.cpp)
target_link_libraries(matrix_demo PRIVATE eigen) # 传递头文件和宏
(3) 目标依赖导入库
bash
# 导入库 的基本声明
add_library(boost_system SHARED IMPORTED)
set_target_properties(boost_system PROPERTIES
# 设置库文件路径
IMPORTED_LOCATION /usr/lib/libboost_system.so
# 设置头文件路径(自动传递给链接者)
INTERFACE_INCLUDE_DIRECTORIES /usr/include/boost
# 添加宏定义
INTERFACE_COMPILE_DEFINITIONS BOOST_SYSTEM_DYN_LINK
)
# 可执行程序目标 链接导入目标
add_executable(network_app main.cpp)
target_link_libraries(network_app PRIVATE boost_system)
# 使用效果:
# (1)编译时:
# 1. 自动添加头文件搜索路径:-I/usr/include/boost
# 2. 自动添加宏定义:-DBOOST_SYSTEM_DYN_LINK
# (2)链接时:
# 1. 链接 库的绝对路径:/usr/lib/libboost_system.so
9. set_target_properties
- 函数作用:
set_target_properties 是 CMake 中用于为特定目标(如可执行文件、静态库、动态库)设置属性的核心命令,通过属性控制目标的输出名称、版本号、目录位置等关键行为
- 函数形式:
bash
set_target_properties(<target1> <target2> ...
PROPERTIES
<prop1> <value1>
<prop2> <value2> ...
)
- 举例说明:
(1) 设置头文件路径(对比 target_include_directories)
方法A:专用命令(推荐)
bash
# 电池传感器库
add_library(battery_sensor STATIC sensor.cpp)
target_include_directories(battery_sensor
INTERFACE include/sensor # 仅传播给依赖者
PRIVATE src/internal # 私有头文件
)
方法B:set_target_properties(不推荐)
bash
add_library(battery_sensor STATIC sensor.cpp)
# 手动设置属性(需区分作用域)
set_target_properties(battery_sensor PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include/sensor" # 仅传播给依赖者
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/src/internal" # 私有路径
)
对比结论:
✅ target_include_directories:自动处理路径转换(可以设置相对路径) 和 作用域
❌ set_target_properties:需手动处理绝对路径(不能设置相对路径) 和 作用域分离
(2) 添加链接库(对比 target_link_libraries)
方法A:专用命令(推荐)
bash
add_executable(bms_controller main.cpp)
target_link_libraries(bms_controller
PUBLIC battery_core # 公共依赖
PRIVATE voltage_monitor # 私有依赖
)
方法B:set_target_properties(不推荐)
bash
add_executable(bms_controller main.cpp)
# 手动设置链接属性
set_target_properties(bms_controller PROPERTIES
INTERFACE_LINK_LIBRARIES "battery_core" # 仅传播给依赖者
LINK_LIBRARIES "battery_core;voltage_monitor" # 私有依赖
)
对比结论:
✅ target_link_libraries:支持作用域关键字
❌ set_target_properties:无法区分作用域,需分开设置
(3) 设置链接目录(对比 target_link_directories)
方法A:专用命令(推荐)
bash
target_link_directories(bms_firmware
PRIVATE ${STM32_HAL}/lib
)
方法B:set_target_properties(不推荐)
bash
set_target_properties(bms_firmware PROPERTIES
LINK_DIRECTORIES "${STM32_HAL}/lib"
)
(4) set_target_properties 专属领域(不可替代)
场景1:动态库版本控制
bash
add_library(battery_algo SHARED algo.cpp)
set_target_properties(battery_algo PROPERTIES
VERSION 2.3.0 # 完整版本
SOVERSION 2 # API版本
OUTPUT_NAME "bms" # 输出文件名
)
生成:libbms.so.2.3.0 (实际) 和 libbms.so.2 (符号链接)
场景2:多配置输出(Debug/Release)
bash
dd_executable(monitor main.cpp)
set_target_properties(monitor PROPERTIES
DEBUG_POSTFIX "_d" # Debug版本后缀
RELEASE_POSTFIX "_release" # Release后缀
)
生成:monitor_d (Debug) 和 monitor_release (Release)
10. file
10.1 file函数的介绍
- 函数作用:
file(GLOB|GLOB_RECURSE) 是 CMake 中 用于模式匹配收集文件列表 的核心命令
- 函数形式:
bash
file(GLOB|GLOB_RECURSE <variable>
[LIST_DIRECTORIES true|false]
[RELATIVE <path>]
[CONFIGURE_DEPENDS]
<globbing-expressions>...
)
- 参数解析:
| 模式 | 作用 | 适用场景 |
|---|---|---|
| GLOB | 非递归匹配当前目录 | 顶层目录文件收集 |
| GLOB_RECURSE | 递归匹配所有子目录 | 深层嵌套文件收集 |
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
| < variable > | 必需 | - | 存储匹配结果的变量名 |
| < globbing-expressions > | 必需 | - | 文件匹配表达式 |
| LIST_DIRECTORIES | 可选 | true | 是否包含匹配的目录 |
| RELATIVE < path > | 可选 | - | 返回相对路径(相对于指定目录) |
| CONFIGURE_DEPENDS | 可选 | - | 自动检测文件变化并重新配置 |
- 举例说明:
bash
# 收集当前目录所有C++源文件
file(GLOB SRC_LISTS
"src/*.cpp"
"src/*.cxx"
)
# 添加可执行文件
add_executable(bms_controller ${SRC_LISTS})
10.2 文件匹配表达式语法(含示例演示)
支持标准通配符和高级特性:
- 基础通配符
| 通配符 | 作用 | 示例 |
|---|---|---|
| * | 匹配任意字符 | *.cpp → 所有C++文件 |
| ? | 匹配单个字符 | ?.h → a.h, b.h |
| [...] | 字符集匹配 | [abc].txt → a.txt, b.txt, c.txt |
| [^...] | 排除字符 | [^test]*.c → 排除test开头的C文件 |
- 高级特性
| 特性 | 语法 | 说明 |
|---|---|---|
| 多模式 | {*.cpp,*.h} | 匹配多个模式 |
| 递归排除 | **/*.cpp (GLOB_RECURSE) | 匹配所有子目录的cpp文件 |
| 转义字符 | \\* | 匹配字面星号 |
(1) 多模式匹配(花括号扩展)
语法:{pattern1,pattern2,...,patternN}
作用:同时匹配多个模式,结果合并到同一个列表中
bash
# 示例1:收集多种类型的源文件
file(GLOB SOURCES
"src/{*.cpp,*.cxx,*.h,*.hpp}"
)
# 匹配结果:
# src/main.cpp
# src/utils.cxx
# src/config.h
# src/logger.hpp
bash
# 示例2:收集多个目录中的特定文件
file(GLOB_RECURSE BMS_FILES
"bms/{algorithms/*.c, sensors/*.c, config/*.json}"
)
# 匹配结果:
# bms/algorithms/soc.c
# bms/algorithms/thermal.c
# bms/sensors/voltage.c
# bms/sensors/temperature.c
# bms/config/settings.json
(2) 递归通配符(**)
语法:**
仅在 GLOB_RECURSE 模式下有效,匹配任意层级的子目录
bash
# 示例3:递归收集所有测试文件
file(GLOB_RECURSE TEST_FILES
"tests/**/*_test.cpp"
)
# 匹配结果:
# tests/unit/battery_test.cpp
# tests/unit/sensor_test.cpp
# tests/integration/system_test.cpp
# tests/performance/stress_test.cpp
bash
# 示例4:递归收集所有文档
file(GLOB_RECURSE DOCS
"docs/**/*.{md,pdf}"
)
# 匹配结果:
# docs/getting_started.md
# docs/api/reference.md
# docs/design/bms_architecture.pdf
(3) 字符转义
语法:\\
匹配特殊字符的字面值
bash
# 示例5:匹配带星号的文件名
file(GLOB SPECIAL_FILES
"config/config_\\*.json" # 匹配字面星号
)
# 匹配文件:
# config/config_*.json
# 不匹配:
# config/config_v1.json
# config/config_v2.json
bash
# 示例6:匹配带问号的文件名
file(GLOB LOG_FILES
"logs/error_\\?.log" # 匹配字面问号
)
# 匹配文件:
# logs/error_?.log