Cmake相关
[TOC]
CMake简介
1. 什么是 CMake?
CMake 是一款跨平台的 构建系统生成工具(Build System Generator),而非直接的构建工具(如 Make、Ninja、Visual Studio 编译器)。它的核心作用是:通过读取开发者编写的 CMakeLists.txt 配置文件,根据不同的操作系统(Windows/macOS/Linux)、编译器(GCC/Clang/MSVC)和构建工具链,自动生成适配当前环境的构建文件(如 Makefile、Visual Studio 的 .sln 解决方案、Ninja 脚本等),最终由这些原生构建工具完成代码的编译、链接等流程。
简单来说,CMake 解决了“跨平台项目构建适配”的痛点——开发者只需写一套 CMake 配置,即可在不同平台上生成符合当地习惯的构建产物,无需手动维护多套 Makefile 或 IDE 工程。
2. CMake 的核心文件结构
CMake 项目的文件结构以 CMakeLists.txt 为核心,配合可选的辅助文件,整体结构清晰且可扩展。
以一个 centos 中的 TK 服务为例介绍基本文件结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
TKTestProj/ # 一个 TKLinux 项目
├── .vscode/ # vscode 读取的配置文件(具体介绍见本文后面相关章节)
│ ├── c_cpp_properties.json # C/C++ 语言配置文件
│ ├── launch.json # 调试配置文件
│ ├── tasks.json # 任务配置文件
│ └── settings.json # 项目级别的 VS Code 配置(覆盖全局设置)
├── build/ # 构建目录(推荐“_out-of-source”构建,手动创建)
├── bin/ # TK 指定的存放编译结果的文件夹(在CMakeLists.txt中指定)
├── .gitignore # git 管理文件
├── CMakeLists.txt # 根级配置文件(必需,项目入口)
├── TKTestProj.cpp # 项目内的 .cpp 文件
├── TKTestProj.h # 项目内的 .h 文件
└── CMakePresets.json # 预设配置文件(可选,简化构建参数)
关键文件说明
-
CMakeLists.txt(核心)
项目的“构建配置脚本”,是 CMake 唯一必需的文件,遵循 CMake 语法规则。根目录的
CMakeLists.txt负责全局配置(如项目名称、最低 CMake 版本、依赖库等),子目录的CMakeLists.txt负责局部配置(如编译当前目录的源文件为库/可执行程序)。 -
build/ 目录(推荐)
用于存放 CMake 生成的构建文件(如 Makefile、.sln)、编译中间产物(.o/.obj 文件)和最终可执行程序。这种“源码与构建产物分离”的方式称为 out-of-source build,可避免污染源码目录,且支持多套构建配置(如 debug/release 各一个 build 目录)。
-
CMakePresets.json(可选)
CMake 3.19+ 支持的“预设文件”,用于预定义构建参数(如编译器路径、构建类型、安装目录等),开发者只需通过
cmake --preset <预设名>即可快速启动构建,无需每次手动输入复杂参数。
3. CMake 的核心功能
CMake 的功能围绕“跨平台构建管理”展开,核心能力可归纳为以下几类:
1)项目基础配置
-
定义项目信息:通过
project()指令指定项目名称、支持的语言(C/C++/Python 等)、版本号。示例:
project(MyProject VERSION 1.0 LANGUAGES CXX)(C++ 项目,版本 1.0)。 -
指定最低 CMake 版本:通过
cmake_minimum_required(VERSION 3.15)确保兼容所需的 CMake 特性。 -
设置构建类型:通过
set(CMAKE_BUILD_TYPE Debug)或set(CMAKE_BUILD_TYPE Release)区分调试/发布版本(Debug 含调试符号,Release 开启优化)。
2)编译目标管理
CMake 通过“目标(Target)”管理编译产物,核心目标类型包括:
- 可执行程序(Executable):通过
add_executable(<目标名> 源文件1 源文件2 ...)生成,如add_executable(myapp src/main.cpp)。 - 库文件(Library):通过
add_library(<目标名> [STATIC/SHARED] 源文件...)生成,分为:STATIC:静态库(如 Windows 的 .lib、Linux 的 .a),编译时直接嵌入可执行程序。SHARED:动态库(如 Windows 的 .dll、Linux 的 .so、macOS 的 .dylib),运行时加载。
示例:将 src/math/add.cpp 编译为静态库 math_lib:
add_library(math_lib STATIC src/math/add.cpp)。
3)依赖与路径管理
- 头文件路径:通过
target_include_directories(<目标名> PUBLIC/PRIVATE <路径>)指定编译时的头文件搜索路径:-
PUBLIC:当前目标和依赖它的目标都能使用该路径。 -
PRIVATE:仅当前目标可用。示例:
target_include_directories(myapp PUBLIC include)(让myapp能引用include/下的头文件)。
-
-
链接库:通过
target_link_libraries(<目标名> <依赖库1> <依赖库2>...)链接静态/动态库。示例:
target_link_libraries(myapp math_lib)(让myapp链接math_lib静态库)。 -
外部依赖查找:通过
find_package(<库名>)自动查找系统中已安装的第三方库(如 Boost、Qt、OpenCV),并获取其头文件路径和库文件路径。示例:
find_package(OpenCV REQUIRED)(查找 OpenCV,找不到则报错)。
4)跨平台适配
-
条件编译:通过
if(<条件>) ... else() ... endif()指令适配不同平台/编译器。示例:区分 Windows 和 Linux 的头文件:
1 2 3 4 5
if(WIN32) target_include_directories(myapp PRIVATE include/win) elseif(UNIX) target_include_directories(myapp PRIVATE include/unix) endif()
-
平台特定宏/编译选项:通过
target_compile_definitions()添加宏定义,target_compile_options()添加编译器参数(如 GCC 的-Wall、MSVC 的/W4)。
5)安装与打包
-
安装配置:通过
install()指令定义编译产物的安装路径(如可执行程序安装到/usr/bin,库文件安装到/usr/lib)。示例:
install(TARGETS myapp DESTINATION bin)(将myapp安装到系统的bin目录)。 -
打包:通过
CPack模块(CMake 内置)生成跨平台安装包(如 Windows 的 .exe 安装器、Linux 的 .deb/.rpm、macOS 的 .dmg),只需在根CMakeLists.txt中添加include(CPack)即可启用。
6)测试集成
通过 CTest 模块(CMake 内置)集成测试框架(如 Google Test),支持自动发现测试用例、批量执行测试并生成报告。
示例:
1
2
3
4
include(CTest)
add_executable(test_math test/test_add.cpp)
target_link_libraries(test_math math_lib gtest gtest_main)
add_test(NAME TestAdd COMMAND test_math) # 注册测试用例
CMake使用场景
1. 简单构建
CMake 的典型工作流分为 3 步,以 Linux 下生成 Makefile 为例:
-
创建并进入 build 目录:
mkdir build && cd build(out-of-source 构建)。 -
生成构建文件:
cmake ..(..表示根目录的 CMakeLists.txt,CMake 会自动生成 Makefile)。若需要指定编译版本的话,在构建时指定参数:
cmake -DCMAKE_BUILD_TYPE=Release .. -
执行构建:
make(通过 Makefile 编译代码,生成可执行程序或库)。
若需安装产物:make install;若需执行测试:make test。
2. 通过 vscode 打开 CMake 的项目
当使用 VS Code 通过 SSH 连接 Linux 进行开发时,项目根目录下自动生成的 .vscode 文件夹是 VS Code 用于存储 项目特定配置 的目录,其中的 launch.json、tasks.json、c_cpp_properties.json 等文件分别对应调试、构建、语言支持等核心功能的配置。这些文件确保 VS Code 能理解项目的构建规则、调试方式和语言特性,从而提供匹配的开发体验。
TKLinux 的项目可以参考 pushlogic 中的文件,一般来说把这里的 .vscode 整个拷贝到其他项目就可以了。
或者将 CMakeLists.txt 文件提供给AI,让AI帮忙生成对应的配置文件即可(主要是c_cpp_properties.json)
1).vscode 目录下核心文件的作用与结构
launch.json:调试配置文件:
作用:定义调试器的启动参数,告诉 VS Code 如何启动程序、设置断点、传递命令行参数等。
适用场景:C/C++、Python、Go 等几乎所有支持调试的语言。
典型结构(以 C++ 为例):
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
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Program", // 调试配置名称(下拉菜单可选)
"type": "cppdbg", // 调试器类型(cppdbg 对应 C++)
"request": "launch", // 启动方式(launch 启动程序,attach 附加到已运行进程)
"program": "${workspaceFolder}/build/myapp", // 待调试程序路径
"args": [], // 传递给程序的命令行参数
"stopAtEntry": false, // 是否在入口处(main 函数)自动暂停
"cwd": "${workspaceFolder}", // 程序运行的工作目录
"environment": [], // 环境变量(如 PATH、LD_LIBRARY_PATH)
"externalConsole": false, // 是否使用外部控制台
"MIMode": "gdb", // 调试器后端(Linux 常用 gdb,Windows 常用 lldb)
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build", // 调试前执行的任务(如关联 tasks.json 中的构建任务)
"miDebuggerPath": "/usr/bin/gdb", // 调试器可执行文件路径
"setupCommands": []
}
]
}
tasks.json:任务配置文件
作用:定义可自动化执行的任务(如编译、构建、格式化代码等),可通过快捷键或调试前自动触发。
适用场景:配合 CMake 构建、Make 编译、脚本执行等。
典型结构(以 CMake 构建为例):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"version": "2.0.0",
"tasks": [
{
"label": "build", // 任务名称(供 launch.json 或命令面板调用)
"type": "shell", // 任务类型(shell 执行命令行,process 直接运行程序)
"command": "cmake --build build", // 构建命令(此处为 CMake 构建)
"args": [], // 命令参数(如 --config Release 指定构建类型)
"group": {
"kind": "build",
"isDefault": true // 是否为默认构建任务
},
"problemMatcher": "$gcc", // 错误匹配规则(解析 gcc 等编译器的报错输出)
"detail": "Generated task for CMake build"
}
]
}
c_cpp_properties.json:C/C++ 语言配置文件
作用:为 C/C++ 扩展提供代码分析所需的配置(如头文件路径、编译器标准、宏定义等),确保语法高亮、智能提示、错误检查正常工作。
适用场景:仅针对 C/C++ 项目(由 VS Code 的 C/C++ 扩展自动生成)。
典型结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"configurations": [
{
"name": "Linux", // 配置名称(对应不同平台)
"includePath": [
"${workspaceFolder}/**", // 递归包含项目内所有头文件
"/usr/include", // 系统头文件路径
"/usr/local/include" // 第三方库头文件路径
],
"defines": [], // 全局宏定义(如 DEBUG=1)
"compilerPath": "/usr/bin/gcc", // 编译器路径(用于解析标准库)
"cStandard": "c17", // C 标准版本
"cppStandard": "c++17", // C++ 标准版本
"intelliSenseMode": "linux-gcc-x64" // 智能提示适配的编译器架构
}
],
"version": 4
}
其他可能的文件
settings.json:项目级别的 VS Code 配置(覆盖全局设置),如缩进空格数、文件编码等。extensions.json:推荐扩展列表(提示开发者安装项目所需的扩展,如 C/C++、CMake Tools 等)。
2)其他 IDE 的类似配置文件结构
不同 IDE 也会通过特定目录或文件存储项目配置,但形式和命名略有差异,核心功能与 VS Code 的 .vscode 目录类似:
Visual Studio(Windows 桌面版)
- 核心配置目录:
.vs/(隐藏目录,存储解决方案缓存、调试配置等,不建议手动修改)。 - 关键文件:
.sln:解决方案文件(类似项目入口,管理多个工程)。.vcxproj:工程文件(对应单个可执行程序或库,包含编译选项、依赖等)。.vcxproj.filters:文件组织结构(定义 IDE 中显示的文件夹结构)。
- 特点:配置与 IDE 深度绑定,可视化界面修改为主,较少手动编辑文件。
CLion(JetBrains 系列,跨平台)
- 核心配置目录:
.idea/(隐藏目录,存储项目所有配置)。 - 关键文件:
CMakeLists.txt:CLion 原生支持 CMake,直接使用 CMake 配置构建(无需额外构建文件)。.idea/workspace.xml:工作区配置(窗口布局、打开的文件等)。.idea/runConfigurations/:调试/运行配置(类似launch.json)。.idea/compiler.xml:编译选项配置(类似tasks.json)。
- 特点:配置文件自动生成,支持通过图形界面修改后同步到文件。
Xcode(macOS 平台)
- 核心配置目录:
.xcodeproj/(项目包,本质是目录)。 - 关键文件:
project.pbxproj:项目核心配置(存储目标、编译选项、依赖等,二进制格式,不建议手动编辑)。.xcworkspace/:工作区文件(管理多个项目的依赖关系)。
- 特点:配置文件为二进制格式,完全通过 Xcode 图形界面操作,几乎不手动编辑。
Eclipse(跨平台,多语言支持)
- 核心配置目录:
.settings/(存储项目特定设置)、.project和.cproject(项目元数据)。 - 关键文件:
.project:项目基本信息(名称、关联的插件等)。.cproject:C/C++ 项目的编译配置(类似c_cpp_properties.json)。.settings/org.eclipse.debug.core.launchConfiguration:调试配置(类似launch.json)。
- 特点:配置文件多为 XML 格式,可手动编辑但更推荐图形界面操作。
3)修改 .vscode 后生效
- 保存
c_cpp_properties.json到项目的.vscode目录下。 - 重新生成 CMake 缓存(在
build目录执行cmake ..),确保compile_commands.json生成(如果启用了该选项)。 - 重启 VS Code 或重新加载窗口(
Ctrl+Shift+P→Reload Window),使配置生效。
这样配置后,VS Code 的 C/C++ 扩展就能正确识别头文件、语法和编译选项,提供准确的代码提示和跳转功能。
3. 用CMake构建项目的例子
4. 使用CMake构建release版本
1)查看 CMakeList.txt 配置
以一个 TKLinux 项目为例,在 CMakeList.txt 中已经定义了如下内容:(拷贝自 PushLogic )
1
2
3
4
5
6
7
8
9
10
11
12
13
if (CMAKE_BUILD_TYPE MATCHES "Debug" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
add_executable(${PROJECT_NAME}_d ${DIR_SRCS})
target_link_libraries(${PROJECT_NAME}_d tkmessage.debug tkmysqlpool.debug tkredispool.debug tksocketlibrary.debug tkasynlog.debug tkthreadpool.debug tkcommon.debug mysqlclient ssl crypto pthread dl uuid)
elseif (CMAKE_BUILD_TYPE MATCHES "Release" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 ")
add_executable(${PROJECT_NAME} ${DIR_SRCS})
target_link_libraries(${PROJECT_NAME} tkmessage tkmysqlpool tkredispool tksocketlibrary tkasynlog tkthreadpool tkcommon mysqlclient ssl crypto pthread dl uuid)
endif (CMAKE_BUILD_TYPE MATCHES "Debug")
CMake 的 CMAKE_BUILD_TYPE 变量决定了构建模式。默认是 Debug(取决于你的环境)的话,直接 cmake .. && make 会生成 Debug 版本;上面那个例子中没有默认项,因此必须先指定编译类型。
若想编译出 Release 版本,必须在 CMake 配置阶段 显式指定 CMAKE_BUILD_TYPE 为 Release(见后面的步骤),因为 CMake 是基于预定义的构建类型(Debug/Release 等)来生成对应 Makefile 的。
2)删除旧的构建产物
避免 Debug 版本的缓存影响
1
2
3
# 进入构建目录(通常是 build 目录,若没有则创建)
cd /path/to/your/project/build # 替换为你的项目构建目录
rm -rf * # 清除旧的 CMake 缓存和编译产物
3)指定构建类型编译
用 CMake 指定 Release 模式重新生成 Makefile :
1
2
3
mkdir build
cd build # 在 build 目录下执行,指定构建类型为 Release
cmake -DCMAKE_BUILD_TYPE=Release ..
-DCMAKE_BUILD_TYPE=Release:这是关键参数,告诉 CMake 生成 Release 模式的配置(对应你 CMakeLists.txt 中elseif (CMAKE_BUILD_TYPE MATCHES "Release")分支)。..表示 CMakeLists.txt 所在的上级目录(根据你的实际目录结构调整,确保指向项目根目录)。
执行 make 编译:
1
make # 此时会根据 Release 配置编译,生成不带 _d 后缀的可执行文件
4)验证是否为 Release 版本:
编译完成后,可查看结果文件的生成路径(这个路径也是在 CMakeList 中指定的)中是否有 release 版本的可执行文件。
或通过以下命令确认: (以 tkmsgmisconfigservice 为例)
1
2
# 查看可执行文件信息
file ../bin/tkmsgmisconfigservice
- 若输出包含
optimized或with debug_info(若 Release 配置加了-g,所以会有调试信息),说明是 Release 版本。 - 对比 Debug 版本(
tkmsgmisconfigservice_d),Release 版本通常体积更小,且不带_d后缀(符合 CMakeLists.txt 中的配置)。
5)思考:
如果需要频繁切换 Debug/Release,建议分别创建两个构建目录(如 build_debug 和 build_release),避免每次清除缓存。
Cmake和xmake和nmake之间的关系
CMake、XMake 和 NMake 是三种不同的构建系统,它们都用于自动化编译过程,但它们在设计理念、功能、使用方式以及支持的平台等方面存在差异。下面是它们之间的一些主要关联和区别:
CMake
- 设计理念:CMake 是一个跨平台的自动化构建系统,它使用配置文件(CMakeLists.txt)来指定构建过程。CMake 可以生成多种构建系统的配置文件,例如 Makefile、Visual Studio 解决方案、Ninja 文件等。
- 功能:CMake 支持大型项目,可以管理多目录、多应用程序的构建,还支持多种编译器和工具链。
- 使用方式:用户通过编写CMakeLists.txt 脚本来配置项目,然后 CMake 会根据这些脚本生成实际的构建文件。
- 平台支持:CMake 支持 Windows、macOS 和 Linux,生成的构建配置可以在各种平台上使用。
XMake
- 设计理念:XMake 是一个基于 Lua 的轻量级跨平台构建工具,它贴近现代编程语言的设计,提供了丰富的API接口和模块,使构建过程更加方便快捷。
- 功能:XMake 提供了包管理的功能,并且可以很容易地集成第三方库。XMake 还针对不同的编程语言和平台提供了专门的支持。
- 使用方式:用户编写xmake.lua脚本文件来描述编译规则,XMake 解析这些脚本并执行构建任务。
- 平台支持:XMake 同样支持 Windows、macOS 和 Linux,并且致力于简化构建过程和提高构建速度。
NMake
- 设计理念:NMake 是微软提供的一个构建工具,通常与 Visual Studio 配合使用,用于基于 Makefile 的项目。
- 功能:功能相对基础,主要用于执行 Makefile 中描述的命令,可以处理项目的依赖关系和构建顺序。
- 使用方式:用户通过编写 Makefile 文件来配置项目,然后使用 NMake 工具按照 Makefile 的描述来编译项目。
- 平台支持:NMake 主要用于 Windows,它是 Visual Studio 的一部分。
关联和区别
- 关联:三者都用于自动化编译和构建软件项目,提供了一种方式来描述和执行构建过程。
- 区别:
- 使用语言:CMake 使用自己的脚本语言,XMake 使用 Lua,NMake 使用类 Unix Makefile。
- 跨平台:CMake 和 XMake 设计为跨平台工具,而 NMake 主要用于 Windows。
- 灵活性:CMake 和 XMake 提供了更多高级特性和灵活性,NMake 相对基础。
- 易用性:XMake 强调简单易用,而 CMake 提供了丰富的功能,但配置相对复杂;NMake 对于习惯使用 Visual Studio 的开发者来说比较熟悉。
- 生成方式:CMake 生成多种构建系统的文件,而 XMake 和 NMake 是直接执行构建的。