news 2026/4/16 20:20:37

CMake工具链实战 - 第1讲 - CMake的来龙去脉

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CMake工具链实战 - 第1讲 - CMake的来龙去脉
日期内容
120260201初版

引言:从"Hello World"的构建困境说起

想象一下这个场景:你写了一个简单的C++程序:

// hello.cpp #include <iostream> int main() { std::cout << "Hello World!" << std::endl; return 0; }

在Linux上,你用gcc编译:

g++ hello.cpp -o hello

在Windows上,你需要用Visual Studio创建项目,添加源文件,配置编译选项...
在macOS上,你可能要用Xcode做类似的事情...

同一个程序,三套不同的构建流程。这就是CMake要解决的核心问题。

一、构建系统的演进史:从Makefile到CMake

1.1 石器时代:手动编译

# 早期开发者的一天 g++ -c main.cpp -o main.o -I./include -std=c++11 g++ -c utils.cpp -o utils.o -I./include -std=c++11 g++ main.o utils.o -o myapp -lm -lpthread

问题:命令冗长,容易出错,难以维护。

1.2 铁器时代:Makefile的出现

# 经典的Makefile CC = g++ CFLAGS = -I./include -std=c++11 OBJS = main.o utils.o myapp: $(OBJS) $(CC) -o myapp $(OBJS) %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f *.o myapp

进步:自动化构建,依赖管理。
局限

  • 语法晦涩(Tab vs 空格问题)

  • 平台差异大(Windows vs Unix)

  • 跨平台需要写多套配置

1.3 工业革命:Autotools(GNU构建系统)

# configure.ac 和 Makefile.am 的组合 # 需要编写:configure.ac, Makefile.am, 运行一系列工具

特点:功能强大,在开源社区广泛使用。
问题:学习曲线陡峭,配置复杂,被戏称为"黑色艺术"。

1.4 现代时代:CMake的诞生

2000年:Kitware公司为了解决ITK(医学图像处理库)的跨平台构建问题,创建了CMake。

核心理念Write once, build everywhere

二、CMake的设计哲学:元构建系统

2.1 什么是"元构建系统"?

CMake不直接编译代码,而是生成其他构建系统需要的文件

你的CMakeLists.txt ↓ CMake ← 配置阶段 ↓ 平台特定的构建文件 ← 生成阶段 ↓ 编译器 ← 构建阶段

CMake可以生成:

  • Unix/Linux: Makefile

  • Windows: Visual Studio项目文件(.sln, .vcxproj)

  • macOS: Xcode项目文件(.xcodeproj)

  • 其他: Ninja构建文件、CodeBlocks项目等

2.2 CMake的核心优势

# 一个简单的CMakeLists.txt示例 cmake_minimum_required(VERSION 3.10) project(MyProject) # 添加可执行文件 add_executable(myapp main.cpp utils.cpp) # 设置C++标准 set(CMAKE_CXX_STANDARD 11) # 包含头文件目录 target_include_directories(myapp PUBLIC include) # 链接库 target_link_libraries(myapp pthread)

一次编写,到处生成

# Linux下生成Makefile cmake -B build -G "Unix Makefiles" # Windows下生成VS项目 cmake -B build -G "Visual Studio 16 2019" # macOS下生成Xcode项目 cmake -B build -G "Xcode"

三、为什么各大开源项目都选择CMake?

3.1 数据说话:CMake的统治地位

项目构建系统说明
LLVM/ClangCMake编译器基础设施
BoostCMake (1.70+)C++标准库的试验场
Qtqmake → CMake著名的GUI框架(Qt6全面转向CMake)
OpenCVCMake计算机视觉库
Google TestCMakeGoogle的C++测试框架
MySQLCMake关系型数据库
BlenderCMake3D创作软件

3.2 选择CMake的五大理由

理由1:真正的跨平台支持

# 同一套CMakeLists.txt在不同平台 $ cmake -B build -G "Unix Makefiles" # Linux $ cmake -B build -G "Visual Studio 2019" # Windows $ cmake -B build -G "Xcode" # macOS

理由2:优秀的依赖管理

# 查找系统库 find_package(OpenCV REQUIRED) find_package(Boost 1.70 COMPONENTS filesystem system) # 现代依赖管理 include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG release-1.11.0 )

理由3:强大的生态系统

  • CTest: 集成测试框架

  • CPack: 打包工具(生成deb, rpm, NSIS安装包等)

  • CDash: 持续集成仪表板

理由4:IDE友好

# 生成各种IDE项目文件 cmake -B build -G "Visual Studio Code - CodeBlocks - Kate" # 所有主流IDE都原生支持CMake

理由5:活跃的社区和文档

  • 超过20年的持续开发

  • 丰富的学习资源

  • 大量的第三方模块

3.3 从反对到拥抱:Qt的CMake转型

历史:Qt长期使用自研的qmake构建系统

# Qt的.pro文件(qmake) QT += core gui TARGET = MyApp SOURCES += main.cpp widget.cpp

转折点:Qt 6宣布全面转向CMake

# Qt 6的CMake配置 find_package(Qt6 COMPONENTS Core Gui Widgets REQUIRED) qt_add_executable(MyApp main.cpp widget.cpp) qt_target_link_libraries(MyApp Qt6::Core Qt6::Gui Qt6::Widgets)

官方解释:CMake提供了更好的性能、更丰富的功能、更广泛的生态系统支持。

四、CMake在现代C++生态中的定位

4.1 C++构建系统的"普通话"

如果把不同的构建系统比作方言:

  • Makefile:广东话(在Unix世界通用)

  • Autotools:文言文(强大但难懂)

  • Visual Studio项目:北京话(在Windows世界通用)

  • CMake:普通话(全国通用)

4.2 现代C++项目的基础设施

现代C++项目 ├── 代码组织:模块化、库化 ├── 构建系统:CMake(事实标准) ├── 包管理:vcpkg/conan + CMake ├── 测试:Google Test + CTest └── 打包:CPack

4.3 CMake与C++标准的演进同步

C++标准CMake支持特性示例
C++11set(CMAKE_CXX_STANDARD 11)基础标准设置
C++14/17目标属性设置target_compile_features(mylib PUBLIC cxx_std_17)
C++20 模块实验性支持CMake 3.28+ 的模块支持
C++23前瞻性支持持续跟进标准发展

五、CMake的挑战与批评

5.1 常见的批评声音

  1. 语法怪异

# 变量引用需要${} set(MY_VAR "hello") # 设置 message(${MY_VAR}) # 使用时要加${} # 但命令参数直接使用 target_link_libraries(myapp ${LIBRARIES})
  1. 新旧语法并存

# 旧式(全局设置) include_directories(include) link_directories(lib) # 新式(目标为中心) target_include_directories(myapp PUBLIC include) target_link_libraries(myapp PUBLIC mylib)
  1. 学习曲线:从简单使用到精通需要时间。

5.2 CMake的改进方向

  • 现代CMake(3.0+):强调目标为中心的设计

  • 更好的错误信息:持续改进用户体验

  • 模块系统:C++20模块的正式支持

  • 性能优化:大型项目的配置速度

六、实战:感受CMake的威力

6.1 创建一个真正的跨平台项目

# CMakeLists.txt cmake_minimum_required(VERSION 3.10) project(CrossPlatformDemo) # 自动检测平台 if(WIN32) message(STATUS "Building on Windows") add_definitions(-DWINDOWS_PLATFORM) elseif(APPLE) message(STATUS "Building on macOS") add_definitions(-DMACOS_PLATFORM) elseif(UNIX) message(STATUS "Building on Linux/Unix") add_definitions(-DLINUX_PLATFORM) endif() # 创建可执行文件 add_executable(demo main.cpp platform_utils.cpp) # 设置C++标准 set_target_properties(demo PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON ) # 包含头文件 target_include_directories(demo PRIVATE include) # 平台特定的链接 if(UNIX AND NOT APPLE) target_link_libraries(demo pthread rt) endif()

6.2 生成不同平台的构建文件

# 1. Linux上生成Makefile cmake -B build-linux -G "Unix Makefiles" # 2. Windows上生成Visual Studio项目(命令行) cmake -B build-windows -G "Visual Studio 16 2019" -A x64 # 3. macOS上生成Xcode项目 cmake -B build-macos -G "Xcode" # 所有平台使用相同的构建命令 cmake --build build-linux cmake --build build-windows --config Release cmake --build build-macos --config Release

例子:

# ========== 基础配置 ========== # 要求 CMake 版本至少 3.19,低于此版本会报错 cmake_minimum_required(VERSION 3.19) # 定义项目名称为 cmake-1,并指定使用 C++ 语言(CXX) project(cmake-1 LANGUAGES CXX) # ========== Qt 依赖 ========== # 查找并加载 Qt6,版本要求 6.5,REQUIRED 表示找不到就失败;需要 Core 和 Widgets 两个模块 find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets) # Qt 官方推荐的通用项目设置(如 C++ 标准、编译选项等) qt_standard_project_setup() # ========== 可执行程序 ========== # 添加一个名为 cmake-1 的可执行程序(最终生成 .exe / app 等) # WIN32:在 Windows 下作为 GUI 程序(不弹控制台窗口) # MACOSX_BUNDLE:在 macOS 下生成 .app 包 # 后面列出参与编译的源文件和 UI 文件 qt_add_executable(cmake-1 WIN32 MACOSX_BUNDLE main.cpp MainWindow.cpp MainWindow.h MainWindow.ui ) # ========== 链接库 ========== # 把 Qt 的 Core、Widgets 库链接到目标 cmake-1 # PRIVATE 表示仅本目标使用,不传递给依赖它的其他目标 target_link_libraries(cmake-1 PRIVATE Qt::Core Qt::Widgets ) # ========== 安装规则 ========== # 引入 GNU 标准安装目录变量(如 BINDIR、LIBDIR 等) include(GNUInstallDirs) # 定义安装时把 cmake-1 放到哪里: # BUNDLE:macOS 的 .app 安装到指定目录 # RUNTIME:可执行文件安装到“安装目录/bin” # LIBRARY:动态库安装到“安装目录/lib” install(TARGETS cmake-1 BUNDLE DESTINATION . RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) # ========== Qt 部署脚本 ========== # 生成一个脚本,用于把 Qt 的 DLL/框架等依赖一起打包(方便发布) # OUTPUT_SCRIPT deploy_script:生成的脚本保存在变量 deploy_script 里 # NO_UNSUPPORTED_PLATFORM_ERROR:在不支持的平台上不报错,只是不生成 qt_generate_deploy_app_script( TARGET cmake-1 OUTPUT_SCRIPT deploy_script NO_UNSUPPORTED_PLATFORM_ERROR ) # 安装时执行该部署脚本,把依赖一并安装 install(SCRIPT ${deploy_script})

执行cmake -> 构建 -> 运行:

七、学习CMake的正确心态

7.1 接受不完美

CMake不是完美的,但它是最实用的解决方案。就像C++本身一样,它承载着历史包袱,但仍在不断进化。

7.2 从实用出发

不要试图一次掌握CMake的所有细节。从解决实际问题开始:

  1. 让我的项目能在不同平台编译

  2. 集成第三方库

  3. 管理多文件项目

  4. 添加测试支持

7.3 拥抱现代CMake

重点关注3.0+版本的"现代CMake"特性,特别是目标为中心的設計模式。

总结:为什么是CMake?

CMake成为C++构建的事实标准,不是因为它是完美的,而是因为:

  1. 解决了真实痛点:真正的跨平台构建

  2. 平衡了各种需求:简单项目易上手,复杂项目够强大

  3. 建立了生态系统:工具链完整,社区活跃

  4. 与时俱进:持续跟进C++标准发展

  5. 获得行业认可:从开源项目到商业软件广泛采用

CMake就像是C++世界的"构建普通话"——它可能不是每个人的母语,但如果你想和整个C++社区交流,掌握它是必不可少的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 15:03:02

链表判环怎么写?AI一秒给出Floyd算法实现

链表判环怎么写&#xff1f;AI一秒给出Floyd算法实现 你有没有在刷 LeetCode 时&#xff0c;被第141题“环形链表”卡住过&#xff1f; 不是不会做&#xff0c;而是——明明知道要用快慢指针&#xff0c;却总在边界条件上反复出错&#xff1a;空链表怎么处理&#xff1f;单节点…

作者头像 李华
网站建设 2026/4/16 14:44:19

C++中的策略模式应用

1、非修改序列算法 这些算法不会改变它们所操作的容器中的元素。 1.1 find 和 find_if find(begin, end, value)&#xff1a;查找第一个等于 value 的元素&#xff0c;返回迭代器&#xff08;未找到返回 end&#xff09;。find_if(begin, end, predicate)&#xff1a;查找第…

作者头像 李华
网站建设 2026/4/16 14:48:10

Meta MusicGen 应用案例:为短视频快速制作原创背景音乐

Meta MusicGen 应用案例&#xff1a;为短视频快速制作原创背景音乐 &#x1f3b5; Local AI MusicGen 镜像直达页 专为创作者打造的轻量级本地音乐生成工作台&#xff0c;无需联网、不传数据、秒级出曲 1. 短视频创作者的真实困境&#xff1a;配乐难、版权贵、耗时长 你是不…

作者头像 李华
网站建设 2026/4/16 14:48:11

VibeVoice ProGPU显存监控脚本:实时跟踪vram usage与推理延迟关联

VibeVoice Pro GPU显存监控脚本&#xff1a;实时跟踪VRAM usage与推理延迟关联 1. 为什么需要监控GPU显存与延迟的联动关系 VibeVoice Pro 的核心价值&#xff0c;不在于它“能说话”&#xff0c;而在于它“说得快、说得稳、说得久”。当你在部署一个面向实时交互场景的语音服…

作者头像 李华
网站建设 2026/4/15 20:41:07

内存映射文件高级用法

1、非修改序列算法 这些算法不会改变它们所操作的容器中的元素。 1.1 find 和 find_if find(begin, end, value)&#xff1a;查找第一个等于 value 的元素&#xff0c;返回迭代器&#xff08;未找到返回 end&#xff09;。find_if(begin, end, predicate)&#xff1a;查找第…

作者头像 李华
网站建设 2026/4/16 11:11:56

实测IndexTTS 2.0的T2E模块:用文字描述就能控制语气情绪

实测IndexTTS 2.0的T2E模块&#xff1a;用文字描述就能控制语气情绪 你有没有试过这样&#xff1a;写好一段台词&#xff0c;心里已经想好了该用什么语气——是带着笑意的调侃&#xff1f;是压低声音的试探&#xff1f;还是突然拔高的震惊&#xff1f;可点下生成按钮后&#x…

作者头像 李华