CMake基础:CMakeLists.txt 文件结构和语法
目录
1.CMakeLists.txt基本结构
2.核心语法规则
3.关键命令详解
4.常用预定义变量
5.变量和缓存
6.变量作用域与传递
7.注意事项
1.CMakeLists.txt基本结构
CMakeLists.txt 是 CMake 构建系统的核心配置文件,采用命令式语法组织项目结构和编译流程。主要用于定义项目的构建规则、依赖关系、编译选项等。每个 CMake 项目通常都有一个或多个 CMakeLists.txt 文件。
一个完整的 CMakeLists.txt 通常包含以下部分:
# 1. CMake 最低版本要求
cmake_minimum_required(VERSION 3.10)# 2. 项目信息
project(MyProject VERSION 1.0.0 LANGUAGES CXX)# 3. 全局配置(可选)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # 生成 compile_commands.json# 4. 查找依赖(可选)
find_package(Threads REQUIRED)
find_package(Boost 1.70 COMPONENTS system REQUIRED)# 5. 添加子目录(可选)
add_subdirectory(src)
add_subdirectory(tests)# 6. 定义目标(可执行文件或库)
add_executable(myapp main.cpp)
add_library(mylib STATIC src/lib.cpp src/utils.cpp)# 7. 配置目标属性
target_include_directories(mylib PUBLIC include)
target_link_libraries(myapp PRIVATE mylib Threads::Threads)
target_compile_definitions(myapp PRIVATE DEBUG_MODE=1)# 8. 安装规则(可选)
install(TARGETS myapp DESTINATION bin)
install(FILES include/mylib.h DESTINATION include)# 9. 测试配置(可选)
enable_testing()
add_test(NAME MyTest COMMAND myapp_test)
2.核心语法规则
1.命令格式
command(arg1 arg2 ...) # 命令名不区分大小写,但参数区分
- 命令和参数用空格或括号分隔。
- 参数可用双引号括起(如包含空格时):
set(NAME "My Project")
。
2.变量引用
set(SOURCE_FILES main.cpp src/foo.cpp)
add_executable(myapp ${SOURCE_FILES}) # 使用 ${} 引用变量
- 变量作用域:当前目录及子目录,可用
PARENT_SCOPE
提升作用域。
3.注释
# 单行注释
4.条件语句
if(WIN32)set(PLATFORM_LIBS ws2_32)
else()set(PLATFORM_LIBS pthread)
endif()target_link_libraries(myapp PRIVATE ${PLATFORM_LIBS})
- 条件表达式:
WIN32
、APPLE
、UNIX
、DEFINED var
、NOT
、AND
、OR
等。
5.循环
foreach(file IN LISTS source_files)message("Processing file: ${file}")
endforeach()
6.函数和宏
# 函数(有独立作用域)
function(print_info name)message("Project name: ${name}")
endfunction()# 宏(直接替换)
macro(add_example name)add_executable(${name} examples/${name}.cpp)
endmacro()print_info(${PROJECT_NAME})
add_example(example1)
3.关键命令详解
1.项目设置
cmake_minimum_required(VERSION <version>)
:指定所需的最低 CMake 版本。project(<name> [VERSION <ver>] [LANGUAGES <langs>])
:定义项目名称、版本和支持的语言。
示例如下:
#1
cmake_minimum_required(VERSION 3.10)
#2
project(MyProject CXX)
2.目标定义
add_executable(<name> <sources>)
:创建可执行文件。add_library(<name> [STATIC|SHARED|MODULE] <sources>)
:创建库(静态 / 共享 / 模块)。add_custom_target(<name> [COMMAND <cmd>] [DEPENDS <deps>])
:创建自定义目标(如构建脚本)。
示例代码:
#1
add_executable(MyExecutable main.cpp other_file.cpp)
#2
add_library(MyLibrary STATIC library.cpp)
#3
add_library(MyLibrary SHARED library.cpp)
3.依赖管理
find_package(<package> [REQUIRED] [VERSION <ver>])
:查找并导入外部包。add_subdirectory(<dir>)
:添加子目录中的 CMakeLists.txt。target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <libs>)
:链接库到目标。-
include_directories(<dirs>...)
示例代码:
#1
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network)
find_package(Qt${QT_VERSION_MAJOR} CONFIG REQUIRED COMPONENTS Widgets Network)#2
add_subdirectory(tutorial)#3
target_link_libraries(QSimpleUpdater PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets PRIVATE Qt${QT_VERSION_MAJOR}::Network)#4
include_directories(${PROJECT_SOURCE_DIR}/include)
4.编译选项
target_include_directories(<target> <PRIVATE|PUBLIC|INTERFACE> <dirs>)
:添加头文件搜索路径。target_compile_definitions(<target> <PRIVATE|PUBLIC|INTERFACE> <defs>)
:添加编译定义(如-DDEBUG
)。target_compile_options(<target> <PRIVATE|PUBLIC|INTERFACE> <options>)
:添加编译选项(如-Wall
)。
示例代码:
#1
target_include_directories(QSimpleUpdater PUBLIC include)
5.安装规则
install(TARGETS target1 [target2 ...][RUNTIME DESTINATION dir][LIBRARY DESTINATION dir][ARCHIVE DESTINATION dir][INCLUDES DESTINATION [dir ...]][PRIVATE_HEADER DESTINATION dir][PUBLIC_HEADER DESTINATION dir])
示例代码:
#1
install(TARGETS <targets>RUNTIME DESTINATION binLIBRARY DESTINATION libARCHIVE DESTINATION lib/static)install(FILES <files> DESTINATION include)
install(DIRECTORY <dir> DESTINATION share)#2
install(TARGETS MyExecutable RUNTIME DESTINATION bin)
6.自定义命令 (add_custom_command 命令)
add_custom_command(TARGET targetPRE_BUILD | PRE_LINK | POST_BUILDCOMMAND command1 [ARGS] [WORKING_DIRECTORY dir][COMMAND command2 [ARGS]][DEPENDS [depend1 [depend2 ...]]][COMMENT comment][VERBATIM]
)
示例代码:
add_custom_command(TARGET MyExecutable POST_BUILDCOMMAND ${CMAKE_COMMAND} -E echo "Build completed."
)
7.测试配置
enable_testing()
add_test(NAME <test_name> COMMAND <executable> <args>)
add_test(NAME <test_name> WORKING_DIRECTORY <dir> COMMAND <cmd>)
4.常用预定义变量
1. 项目信息
变量名 | 描述 | 示例值 |
---|---|---|
PROJECT_NAME | 当前项目名称 | MyProject |
PROJECT_VERSION | 项目版本(通过 project() 设置) | 1.2.3 |
PROJECT_SOURCE_DIR | 当前项目的源目录 | /path/to/myproject |
PROJECT_BINARY_DIR | 当前项目的构建目录 | /path/to/myproject/build |
2.路径相关
变量名 | 描述 | 示例值 |
---|---|---|
CMAKE_SOURCE_DIR | 顶级 CMakeLists.txt 所在目录 | /path/to/myproject |
CMAKE_BINARY_DIR | 顶级构建目录 | /path/to/myproject/build |
CMAKE_CURRENT_SOURCE_DIR | 当前 CMakeLists.txt 所在目录 | /path/to/myproject/src |
CMAKE_CURRENT_BINARY_DIR | 当前构建目录 | /path/to/myproject/build/src |
CMAKE_INSTALL_PREFIX | 安装路径前缀 | /usr/local (默认) |
LIBRARY_OUTPUT_PATH | 库文件输出的默认路径 | 库路径不设置的话,默认放在BINARY_DIR下,即构建时执行cmake命令的目录下 |
3.构建配置
变量名 | 描述 | 示例值 |
---|---|---|
CMAKE_BUILD_TYPE | 构建类型 | Debug , Release , RelWithDebInfo |
CMAKE_C_COMPILER | C 编译器路径 | /usr/bin/gcc |
CMAKE_CXX_COMPILER | C++ 编译器路径 | /usr/bin/g++ |
CMAKE_CXX_STANDARD | C++ 标准版本 | 11 , 14 , 17 , 20 |
CMAKE_GENERATOR | 当前使用的生成器 | Unix Makefiles , Ninja |
CMAKE_C_STANDARD_REQUIRED |
| |
CMAKE_CXX_STANDARD_REQUIRED |
| set(CMAKE_CXX_STANDARD 20) # 指定 C++ 标准为 C++20 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 强制要求此标准 |
| | |
4.系统信息
变量名 | 描述 | 示例值 |
---|---|---|
CMAKE_SYSTEM_NAME | 操作系统名称 | Linux , Windows , Darwin |
CMAKE_SYSTEM_VERSION | 系统版本 | 10.0 (Windows) |
CMAKE_HOST_SYSTEM_PROCESSOR | 处理器架构 | x86_64 , arm64 |
5.目标属性(Target Properties)
通过 set_target_properties
或 get_target_property
操作,影响特定目标的行为。
常用属性
属性名 | 描述 | 设置命令 |
---|---|---|
OUTPUT_NAME | 输出文件名 | set_target_properties(myapp PROPERTIES OUTPUT_NAME "custom_name") |
VERSION | 库版本号 | set_target_properties(mylib PROPERTIES VERSION "1.2.3") |
SOVERSION | 共享库 API 版本 | set_target_properties(mylib PROPERTIES SOVERSION "1") |
COMPILE_DEFINITIONS | 编译定义(如 -DDEBUG ) | target_compile_definitions(myapp PRIVATE DEBUG) |
INCLUDE_DIRECTORIES | 头文件搜索路径 | target_include_directories(myapp PUBLIC include) |
LINK_LIBRARIES | 链接库 | target_link_libraries(myapp PRIVATE pthread) |
POSITION_INDEPENDENT_CODE | 是否生成位置无关代码(共享库必需) | set_target_properties(mylib PROPERTIES POSITION_INDEPENDENT_CODE ON) |
5.变量和缓存
CMake 使用变量来存储和传递信息,这些变量可以在 CMakeLists.txt 文件中定义和使用。
变量可以分为普通变量和缓存变量。
1.变量定义与使用
定义变量:
set(MY_VAR "Hello World")
使用变量:
message(STATUS "Variable MY_VAR is ${MY_VAR}")
2.缓存变量
缓存变量存储在 CMake 的缓存文件中,用户可以在 CMake 配置时修改这些值。缓存变量通常用于用户输入的设置,用户可通过命令行(-D
)或 CMake GUI 修改,例如编译选项和路径。
定义缓存变量:
set(MY_CACHE_VAR "DefaultValue" CACHE STRING "A cache variable")set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries")
set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Installation directory")
使用缓存变量:
message(STATUS "Cache variable MY_CACHE_VAR is ${MY_CACHE_VAR}")
3.环境变量
- 访问方式:
$ENV{VARIABLE_NAME}
- 修改方式:
set(ENV{VARIABLE_NAME} value)
message("PATH: $ENV{PATH}") # 读取环境变量
set(ENV{MY_LIB_PATH} "${CMAKE_SOURCE_DIR}/libs") # 设置环境变量
6.变量作用域与传递
- 默认作用域:当前目录及子目录。
- 提升作用域:
PARENT_SCOPE
参数。
# 在子目录 CMakeLists.txt 中
set(CHILD_VAR "value" PARENT_SCOPE) # 将变量传递到父目录
7.注意事项
1.模块化结构
project/
├── CMakeLists.txt # 顶级配置
├── src/ # 源代码
│ └── CMakeLists.txt
├── include/ # 公共头文件
├── tests/ # 测试代码
│ └── CMakeLists.txt
├── examples/ # 示例
└── CMakeModules/ # 自定义 CMake 模块
2.使用现代 CMake 模式
- 优先使用
target_*
命令(如target_include_directories
)而非全局设置。 - 通过
PUBLIC/PRIVATE/INTERFACE
明确依赖范围。
3.避免硬编码路径
# 不好的做法
include_directories("/usr/local/include/mylib")# 好的做法
find_package(MyLib REQUIRED)
target_link_libraries(myapp PRIVATE MyLib::MyLib)
4.添加版本控制
project(MyProject VERSION 1.2.3)
configure_file(version.h.in version.h)
target_include_directories(myapp PRIVATE ${CMAKE_BINARY_DIR})
掌握 CMakeLists.txt 的结构和语法是高效管理 C/C++ 项目的关键,合理组织文件可大幅提升项目的可维护性和跨平台兼容性。
相关链接
- CMake 官网 CMake - Upgrade Your Software Build System
- CMake 官方文档:CMake Tutorial — CMake 4.0.2 Documentation
- CMake 源码:https://github.com/Kitware/CMake
- CMake 源码:Sign in · GitLab
相关文章:
CMake基础:CMakeLists.txt 文件结构和语法
目录 1.CMakeLists.txt基本结构 2.核心语法规则 3.关键命令详解 4.常用预定义变量 5.变量和缓存 6.变量作用域与传递 7.注意事项 1.CMakeLists.txt基本结构 CMakeLists.txt 是 CMake 构建系统的核心配置文件,采用命令式语法组织项目结构和编译流程。主要用于…...

PCM音频数据的编解码
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据 总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:…...
WebView2 Win7下部分机器触屏失效的问题
这个问题官方给了解决的方案,相关地址,只需要在项目中运行这个代码即可 public static void DisableWPFTabletSupport(){TabletDeviceCollection devices Tablet.TabletDevices;if (devices.Count > 0){Type inputManagerType typeof(InputManager)…...

Ubuntu 通过指令远程命令行配置WiFi连接
前提设备已经安装了无线网卡。 1、先通过命令行 ssh 登录机器。 2、搜索wifi设备,指令如下: sudo nmcli device wifi 3、输入需要联接的 wifi 名称和对应的wifi密码,指令如下: sudo nmcli device wifi connect wifi名称 passw…...
线程池优雅关闭的哲学
引言 关于并发的哲学,本文将着重强调那些关于线程池优雅关闭的一些技巧,希望对你有所启发。 强制关闭线程池的弊端 对于池化的线程池,如果采用强制关闭的方式将线程池直接关闭,就可能存在上下文消息消息,无法的很好…...
11.8 LangGraph生产级AI Agent开发:从节点定义到高并发架构的终极指南
使用 LangGraph 构建生产级 AI Agent:LangGraph 节点与边的实现 关键词:LangGraph 节点定义, 条件边实现, 状态管理, 多会话控制, 生产级 Agent 架构 1. LangGraph 核心设计解析 LangGraph 通过图结构抽象复杂 AI 工作流,其核心要素构成如下表所示: 组件作用描述代码对应…...

8天Python从入门到精通【itheima】-41~44
目录 41节-while循环的嵌套应用 1.学习目标 2.while循环的伪代码和生活情境中的应用 3.图片应用的代码案例 4.代码实例【Patrick自己亲手写的】: 5.whlie嵌套循环的注意点 6.小节总结 42节-while循环的嵌套案例-九九乘法表 1.补充知识-print的不换行 2.补充…...

深度图数据增强方案-随机增加ROI区域的深度
主要思想:随机增加ROI区域的深度,模拟物体处在不同位置的形态。 首先打印一张深度图中的深度信息分布: import cv2 import matplotlib.pyplot as plt import numpy as np import seaborn as sns def plot_grayscale_histogram(image_path)…...
[Java恶补day6] 15. 三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组。 示例 1&a…...
Django模板及表单
什么是Django模板 Django模板是一种用于生成动态内容的文件,它使用Django模板语言(Django Template Language,简称DTL)来描述和渲染HTML页面。模板允许开发人员将动态数据与静态HTML结构分离,以实现更灵活和可维护的W…...

两个mysql的maven依赖要用哪个?
背景 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId> </dependency>和 <dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId> &l…...

Kafka Consumer工作流程
Kafka Consumer工作流程图 1、启动与加入组 消费者启动后,会向 Kafka 集群中的某个 Broker 发送请求,请求加入特定消费者组。这个 Broker 中的消费者协调器(Consumer Coordinator)负责管理消费者组相关事宜。 2、组内分区分配&am…...

大腾智能 PDM 系统:全生命周期管理重塑制造企业数字化转型路径
在当今激烈的市场竞争中,产品迭代速度与质量已成为企业生存与发展的核心命脉。面对客户需求多元化、供应链协同复杂化、研发成本管控精细化等挑战,企业亟需一套能够贯穿产品全生命周期的数字化解决方案。 大腾智能PDM系统通过构建覆盖设计、研发、生产、…...
GATT 服务的核心函数bt_gatt_discover的介绍
目录 概述 1 GATT 基本概念 1.1 GATT 的介绍 1.2 GATT 的角色 1.3 核心组件 1.4 客户端操作 2 bt_gatt_discover函数的功能和应用 2.1 函数介绍 2.1 发现类型(Discover Type) 3 典型使用流程 3.1 服务发现示例 3.2 级联发现模式 3.3 按UUID过…...

【短距离通信】【WiFi】WiFi7关键技术之4096-QAM、MRU
目录 3. 4096-QAM 3.1 4096-QAM 3.2 QAM 的阶数越高越好吗? 4. MRU 4.1 OFDMA 和 RU 4.2 MRU 资源分配 3. 4096-QAM 摘要 本章主要介绍了Wi-Fi 7引入的4096-QAM对数据传输速率的提升。 3.1 4096-QAM 对速率的提升 Wi-Fi 标准一直致力于提升数据传输速率&a…...
C 语言学习笔记
文章目录 程序设计入门 --- C 语言第一周 程序设计与 C 语言1 计算机与编程语言:计算机怎么做事情的,编程语言是什么📒 1.1 计算机的普遍应用 —— 离了它,现代人可能不会“活”了**🌐 科学计算:计算机的“最强大脑”时刻****📊 数据处理:现代社会的“数字管家”***…...
【MySQL成神之路】MySQL函数总结
以下是MySQL函数的全面总结,包含概念说明和代码示例: 一、MySQL函数分类 1. 字符串函数 -- CONCAT:连接字符串 SELECT CONCAT(Hello, , World); -- 输出 Hello World -- SUBSTRING:截取子串 SELECT SUBSTRING(MySQL, 2, 3…...

线程池实战——数据库连接池
引言 作者在前面写了很多并发编程知识深度探索系列文章,反馈得知友友们收获颇丰,同时我也了解到友友们也有了对知识如何应用感到很模糊的问题。所以作者就打算写一个实战系列文章,让友友们切身感受一下怎么应用知识。话不多说,开…...
修改 vue-pdf 源码升级 pdfjs-dist 包, 以解决部分 pdf 文件显示花屏问题
文章目录 背景: 客户反馈有部分文件预览花屏 最终解决方案: 自己 fork vue-pdf 仓库, 修改 pdfjs-dist 版本, 升级到 3.3.122 (我是 vue2 项目 node 10 环境)修改源码中引用地址带有 pdfjs-dist/es5/ 的地方, 去掉 es5 , 另外如果还有报错自己搜一下 pdfjs-dist/ , 看看引用…...

基于moonshot模型的Dify大语言模型应用开发核心场景
基于moonshot模型的Dify大语言模型应用开发核心场景学习总结 一、Dify环境部署 1.Docker环境部署 这里使用vagrant部署,下载vagrant之后,vagrant up登陆,vagrant ssh,在vagrant 中使用 vagrant centos/7 init 快速创建虚拟机 安装…...

华为OD机试真题——字符串序列判定(2025B卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
2025 B卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…...
在Java的list.forEach(即 Stream API 的 forEach 方法)中,无法直接使用 continue 或 break 语句的解决办法
说明 在 Java 的 list.forEach(即 Stream API 的 forEach 方法)中,无法直接使用 continue 或 break 语句,因为它是一个终结操作(Terminal Operation),依赖于 Lambda 表达式或方法引用。 有些时…...
Java面向对象高级学习笔记
面向对象高级 -类变量 类变量-提出问题 提出问题的主要目的就是让大家思考解决之道,从而引出我要讲的知识点 说:有一群小孩在玩堆雪人,不时有新的小孩加入,请问如何知道现在共有多少人在玩?,编写程序解决。 类变量快速入门 思考: 如果,设计一个int co…...
LLM之Agent:Mem0的简介、安装和使用方法、案例应用之详细攻略
LLM之Agent:Mem0的简介、安装和使用方法、案例应用之详细攻略 目录 Mem0的简介 1、Mem0的特点 2、性能: Mem0的安装及使用方法 1、安装 2、基本用法(基本用法) Mem0的案例应用 Mem0的简介 Mem0(发音为“mem-ze…...

工商总局可视化模版-Echarts的纯HTML源码
概述 基于ECharts的工商总局数据可视化HTML模版,帮助开发者快速搭建专业级工商广告数据展示平台。这款模版设计规范,功能完善,适合各类工商监管场景使用。 主要内容 本套模版采用现代化设计风格,主要包含以下核心功能模块&…...

Spring AI 和 Elasticsearch 作为你的向量数据库
作者:来自 Elastic Josh Long, Philipp Krenn 及 Laura Trotta 使用 Spring AI 和 Elasticsearch 构建一个完整的 AI 应用程序。 Elasticsearch 原生集成了业界领先的生成式 AI 工具和服务提供商。查看我们关于超越 RAG 基础或使用 Elastic 向量数据库构建生产级应用…...
阿里云OSS Api工具类不使用sdk
本文工具实现了OSS简单的上传、下载、获取bucket列表功能,一个工具类搞定,不用集成oss sdk v1签名算法 v1算法(v1算法将在2025年9月停用,旧的key不受影响,新key必须用v4) v1签名工具类OssV1Signer.java …...

集群聊天服务器学习 配置开发环境(VScode远程连接虚拟机Linux开发)(2)
配置远程开发环境 第一步:Linux系统运行sshd服务 第二步:在vscode上安装Remote Deve I opment插件,其依赖插件会自动安装 第三步:配置远程Linux主机的信息 第四步:在vscode上开发远程连接Linux 第一步:…...

rabbitmq的使用介绍
一.队列工作模式介绍 1.WorkQueues模型 生产者直接把消息发送给队列,然后消费者订阅队列 特点: 消息不会重复, 分配给不同的消费者. 代码实现: 消费者代码: Component Slf4j public class SpringRabbitListener {RabbitListener(queues &q…...
前端的core-js是什么?有什么作用?
core-js 是前端生态中一个重要的 JavaScript 标准库 polyfill,它的主要作用是为不同浏览器环境提供 ECMAScript 最新特性 和 API 的兼容性支持。以下是其核心作用的详细解析: 一、core-js 是什么? 本质:一个模块化的 JavaScript …...