简述CMake
CMake是一款跨平台的开源构建工具,广泛用于C/C++项目的构建与管理。它通过简洁的配置脚本描述项目结构,并能根据这些脚本生成适用于不同平台和编译环境的构建系统(如Makefile、Visual Studio工程文件等),从而实现高效的跨平台开发。
核心特性
- 跨平台支持:可在Linux、Windows、macOS等多个操作系统上运行,兼容多种编译器(GCC、Clang、MSVC等)和IDE。
- 配置文件清晰:使用名为CMakeLists.txt的文本文件定义构建逻辑,语法直观易懂,便于维护。
- 模块化组织能力:支持将大型项目拆分为多个子目录,每个子目录可独立管理源码、库或组件。
- 多构建配置:支持同时生成Debug与Release版本的构建目标,方便在不同场景下切换。
- 测试集成机制:内置CTest模块,可直接添加单元测试并执行自动化测试流程。
- 依赖管理功能:可通过FetchContent或find_package等方式自动获取并集成第三方库。
- 自定义构建规则:允许用户定义特定命令或行为,满足复杂项目的特殊需求。
接下来的内容将逐步解析《CMake的使用》教程中的各个关键部分,帮助读者系统掌握其用法。
第一部分:环境搭建
目标是在Ubuntu系统中完成CMake的安装与验证。
执行以下命令进行安装:
sudo apt install cmake
安装完成后,使用如下命令检查是否成功:
cmake --version
示例中所使用的CMake版本为3.16.3。此步骤主要用于确保开发环境已准备就绪。
第二部分:简单入门
本节旨在创建一个最基础的CMake项目,熟悉基本操作流程。
项目结构
yhpcmake/ ├── CMakeLists.txt └── main.cpp
关键文件内容
main.cpp:输出“hello yhping”的简单程序。
CMakeLists.txt 内容如下:
cmake_minimum_required(VERSION 3.0) project(demo) add_executable(main main.cpp)
编译流程
- 在源码目录下运行命令生成Makefile:
- 执行编译:
- 生成可执行文件:
- 运行程序查看输出结果:
cmake .
make
main
./main
注意事项
执行编译后会生成大量中间产物(如CMakeCache.txt、CMakeFiles/等):
cmake
CMakeCache.txt
Makefile
若需清理所有生成文件,可使用:
make clean
该部分完整展示了CMake的标准工作流:配置 → 生成 → 编译 → 运行。
第三部分:编译多个源文件
3.1 同一目录下的多文件编译
简单方式
直接在add_executable中列出所有源文件:
add_executable(main main.cpp funa.cpp)
进阶方法
利用AUX_SOURCE_DIRECTORY自动收集当前目录下的所有源文件:
aux_source_directory(. SRC_LIST)
然后在构建目标中引用变量:
add_executable(main ${SRC_LIST})
add_executable
手动指定文件列表
使用set()指令显式定义源文件集合:
set
set(SRC_LIST ./main.cpp ./funa.cpp ./funb.cpp)
3.2 跨目录的多源文件管理
项目结构示例
project_root/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ └── utils.cpp
└── include/
└── utils.h
关键命令说明
在主CMakeLists.txt中包含子目录,并设置头文件搜索路径:
include_directories(include) add_subdirectory(src)
在src/CMakeLists.txt中定义目标:
add_executable(app main.cpp utils.cpp)
第四部分:项目级的组织结构
典型项目布局
MyProject/ ├── CMakeLists.txt ├── src/ │ └── CMakeLists.txt ├── lib/ │ └── CMakeLists.txt ├── include/ │ └── mylib.h └── build/
核心命令
在根目录CMakeLists.txt中调用子目录:
add_subdirectory(src) add_subdirectory(lib)
使用target_include_directories()为特定目标设置头文件路径:
target_include_directories(target_name PUBLIC include/)
两种常用写法对比
- 集中式写法:所有构建逻辑集中在根CMakeLists.txt中,适合小型项目。
- 分布式写法:每个子目录拥有自己的CMakeLists.txt,更利于模块化管理和团队协作。
第五部分:动态库与静态库的编译控制
5.1 生成库文件
项目结构
library_demo/
├── CMakeLists.txt
├── src/
│ └── math_func.cpp
└── include/
└── math_func.h
关键命令
创建静态库:
add_library(math STATIC src/math_func.cpp)
创建动态库:
add_library(math SHARED src/math_func.cpp)
导出头文件路径:
target_include_directories(math PUBLIC include)
5.2 链接库文件
项目结构
app_with_lib/ ├── CMakeLists.txt ├── main.cpp └── libmath.a (或 .so)
关键命令
链接外部库到可执行文件:
target_link_libraries(myapp math)
若库位于非标准路径,需指定库搜索目录:
link_directories(${PROJECT_SOURCE_DIR}/lib)
第六部分:条件编译
6.1 添加编译选项
使用option()命令定义可选开关:
option(ENABLE_DEBUG_LOG "Enable debug logging" ON)
6.2 使用option控制编译行为
控制是否编译某个目标
if(ENABLE_TOOLS) add_executable(tool tool.cpp) endif()
控制代码中的宏定义
在CMake中传递宏:
if(ENABLE_DEBUG_LOG) target_compile_definitions(myapp PRIVATE DEBUG_LOG) endif()
对应C++代码中可通过#ifdef DEBUG_LOG启用调试输出。
命令行控制方式
在cmake命令中通过-D参数开启或关闭选项:
cmake -DENABLE_DEBUG_LOG=ON ..
第七部分:CJSON库的链接实践
关键命令
查找并链接cjson库:
find_package(cjson REQUIRED) target_link_libraries(myapp cjson::cjson)
若系统未安装,可通过FetchContent从GitHub拉取:
include(FetchContent) FetchContent_Declare( cjson GIT_REPOSITORY https://github.com/DaveGamble/cJSON.git GIT_TAG v1.7.14 ) FetchContent_MakeAvailable(cjson)
注意事项
- 确保cjson头文件路径正确暴露给目标。
- 注意版本兼容性,推荐固定Git标签以避免变动。
- 使用命名空间形式(如cjson::cjson)提升链接安全性。
第八部分:CMake项目在VSCode中的调试配置
8.1 两种主要配置文件
- launch.json:定义调试启动参数,如程序路径、参数、环境变量等。
- tasks.json:定义预构建任务,例如调用cmake和make。
8.2 示例配置
tasks.json 示例:
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "cmake --build ./build"
}
]
}
launch.json 示例:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/main",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{ "text": "-enable-pretty-printing" }
],
"preLaunchTask": "build"
}
]
}
第九部分:CMake语法与常用变量
语法特点
- 不区分大小写的关键字(但变量名区分)。
- 使用
set()赋值,${VAR}引用变量。 - 支持函数、宏、条件判断、循环等结构化语法。
常用指令
| cmake_minimum_required | 设定最低CMake版本 |
| project | 定义项目名称 |
| add_executable | 添加可执行目标 |
| add_library | 添加库目标 |
| target_link_libraries | 链接依赖库 |
| include_directories | 添加头文件路径(旧式) |
| target_include_directories | 为特定目标添加头文件路径(推荐) |
| set | 设置变量 |
| option | 定义布尔型配置选项 |
常用内置变量
- CMAKE_CXX_COMPILER:C++编译器路径
- CMAKE_BUILD_TYPE:构建类型(Debug/Release)
- PROJECT_SOURCE_DIR:项目根目录
- CMAKE_CURRENT_SOURCE_DIR:当前CMakeLists所在目录
- CMAKE_BINARY_DIR:构建输出目录
总结
《CMake的使用》是一份结构清晰、循序渐进的CMake学习指南。从环境配置起步,涵盖单文件构建、多文件处理、库的生成与链接、条件编译、外部依赖集成,直至VSCode调试环境搭建,全面覆盖了现代C/C++项目开发所需的核心技能。通过本教程的学习,开发者能够快速掌握CMake的基本用法,并具备构建中大型项目的实际能力。
3.2 多目录下多个源文件的管理
项目结构示例如下:
yhpcmake
├── CMakeLists.txt
├── main.cpp
├── tfuna/
│ ├── funa.cpp
│ └── funa.hpp
└── tfunb/
├── funb.cpp
└── funb.hpp
核心命令说明:
include_directories(tfuna tfunb)
用于添加头文件的搜索路径,确保编译器能够找到所需的 .hpp 文件。
aux_source_directory
通过该命令收集分布在不同子目录中的源文件,便于统一管理与构建。
本节内容旨在引导读者掌握如何组织包含多个源文件和多级目录的项目,并利用 CMake 实现高效构建与维护。
第四部分:项目级别的结构组织
目标:将源码、头文件、构建中间文件及最终输出文件分别归类存放,提升项目整体清晰度与可维护性。
推荐的项目结构如下:
yhpcmake ├── bin/ # 存放生成的可执行程序 ├── build/ # 构建过程产生的中间文件目录 ├── include/ # 集中存放所有公共头文件 │ ├── funa.hpp │ └── funb.hpp ├── src/ # 所有源代码文件所在目录 │ ├── funa.cpp │ ├── funb.cpp │ ├── main.cpp │ └── CMakeLists.txt └── CMakeLists.txt
关键指令包括:
add_subdirectory(src)
用于递归或显式地编译指定子目录下的源码内容。
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
设定最终生成的可执行文件的输出位置,通常指向 bin/ 目录。
两种常见的组织方式:
- 多 CMakeLists.txt 方案:顶层 CMakeLists 控制全局配置,各子目录内的 CMakeLists 负责局部构建逻辑。
- 单一 CMakeLists.txt 方案:在根目录中直接列出所有源文件路径并设置头文件包含路径,适用于小型项目。
此部分内容强调了项目结构的规范性和构建目录的隔离原则,有效防止构建产物混入源码目录,保持代码仓库整洁。
第五部分:静态库与动态库的构建与链接控制
5.1 库文件的生成
示例项目布局:
yhpcmake ├── build/ ├── lib/ ├── tfuna/ │ ├── funa.cpp │ └── funa.hpp └── CMakeLists.txt
涉及的关键命令有:
add_library(tfuna_shared SHARED ${SRC_LIST})
用于创建共享库(即动态库),扩展名为 .so(Linux)或 .dll(Windows)。
add_library(tfuna_static STATIC ${SRC_LIST})
用于生成静态库,扩展名为 .a(Linux)或 .lib(Windows)。
set_target_properties
自定义输出库的名称,支持去除默认前缀或后缀,实现更灵活的命名控制。
set(LIBRARY_OUTPUT_PATH ...)
指定生成的库文件存放路径,一般指向项目的 lib/ 目录。
5.2 库文件的链接使用
使用场景示例结构:
testlib ├── src/ │ └── testmain.cpp ├── tfuna/ │ ├── include/ │ │ └── funa.hpp │ └── lib/ │ ├── libtfuna.a │ └── libtfuna.so └── CMakeLists.txt
主要命令如下:
find_library(TFUNA_LIB tfuna HINTS ...)
在系统或指定路径中查找所需链接的库文件。
target_link_libraries(main ${TFUNA_LIB})
将查找到的库文件链接到目标可执行程序中,完成依赖集成。
本章节深入讲解了静态库与动态库的生成流程及其在实际项目中的调用方法,是 C/C++ 工程实践中不可或缺的核心技能。
第六部分:条件编译机制的应用
6.1 编译选项的添加
使用该命令可在 CMake 配置阶段传入自定义参数,影响后续构建行为。
6.2 基于条件的编译控制
可用于控制是否构建特定目标文件,例如:
option(MYDEBUG "启用调试编译" OFF) if(MYDEBUG) add_executable(main_2 main_2.cpp) endif()
也可用于控制代码中的宏定义开关:
option(YYY1 "启用 YYY1 宏" OFF) if(YYY1) add_definitions(-DYYY1) endif()
从命令行启用选项的方式:
cmake .. -DMYDEBUG=ON
add_compile_options(-std=c++2a -Wall)
option
本部分内容帮助开发者掌握如何借助 CMake 实现编译时的条件判断,灵活区分调试版本与发布版本的构建逻辑。
第七部分:集成第三方库 —— 以 jsoncpp 为例
目标:演示如何在 CMake 项目中正确链接外部第三方库(如 jsoncpp)。
核心命令:
target_link_libraries(testjson libjsoncpp.so)
用于将 jsoncpp 的动态库链接至当前目标。
注意事项:
需提前在系统中安装 jsoncpp 的开发包,例如通过包管理器安装 libjsoncpp-dev 等组件。
libjsoncpp-dev
本节展示了如何对接已安装在系统环境中的第三方库,满足实际工程中对功能扩展的需求。
第八部分:CMake 项目在 VSCode 中的调试配置
8.1 主要配置文件类型
- tasks.json:定义构建任务,如执行 cmake 编译命令。
- launch.json:配置调试器(如 GDB),设置启动参数、程序路径等。
8.2 典型配置示例
在
launch.json
中配置
"preLaunchTask"
,实现启动调试前自动触发编译动作,确保运行的是最新代码。
支持设置断点、单步执行、变量查看等标准调试功能。
本节内容实现了 CMake 构建系统与现代开发工具链(VSCode)的无缝整合,显著提升开发效率与调试体验。
第九部分:CMake 语法基础与常用变量
语法特性说明:
- CMake 指令不区分大小写,但变量名区分大小写。
- 通过
${}
形式获取变量值。
注释符号为:
#
常用指令汇总:
cmake_minimum_required
project
set
include_directories
add_executable
add_library常用变量:
CMAKE_CXX_FLAGS:C++ 编译选项。
CMAKE_BUILD_TYPE:编译类型(Debug/Release)。
EXECUTABLE_OUTPUT_PATH/LIBRARY_OUTPUT_PATH:输出路径。
target_link_libraries
add_subdirectory
aux_source_directory
总结:
本教程以最基础的 Hello World 程序为起点,循序渐进地讲解了多目录项目管理、静态库与动态库的生成及链接、条件编译的实现方式、第三方库的集成方法以及调试环境的配置等内容。涵盖了 CMake 的核心功能与实际应用技巧,结构清晰,内容全面,非常适合初学者系统性地掌握 CMake 的基本用法和项目构建流程。


雷达卡


京公网安备 11010802022788号







