CMake 学习指南(三):CMake 与 Visual Studio 协作
📚 文档系列说明
本文是CMake 学习指南系列的第三篇,深入讲解 CMake 与 Visual Studio 的协作机制。
系列文档目录:
- 📖 第一篇:CMake 基础概念与快速入门
- 📖 第二篇:CMake 项目构建实战
- 📖第三篇:CMake 与 Visual Studio 协作(当前文档)
- 📖 第四篇:CMake 配置项详解
- 📖 第五篇:CMake 语法深入
- 📖 第六篇:跨平台编译与 CMake
- 📖 第七篇:CMake 高级技巧与最佳实践
前置知识:阅读本文前,请确保已掌握第一篇和第二篇中的基础概念。
推荐阅读顺序:
- 新手入门:第一篇 → 第二篇 → 第三篇
- 深入理解:第四篇 → 第五篇 → 第六篇
- 进阶提升:第七篇
目录
- 1. VS 为什么需要 CMake
- 2. VS 和 CMake 的关系
- 3. Visual Studio 使用 CMake 的两种方式
- 4. 方式一:VS 直接打开 CMake 项目
- 5. 方式二:CMake 生成 .sln 文件
- 6. 配置阶段 vs 编译阶段
- 7. 什么时候需要重新生成 .sln
- 8. VS 的 CMake 集成机制
- 9. 两种方式对比与选择
- 10. 总结与下一步
1. VS 为什么需要 CMake
1.1 VS 本身就能编译,为什么还要 CMake?
VS 确实可以独立完成编译,不需要 CMake。你完全可以:
- 打开 VS → 新建项目 → 选择 C++ 项目模板
- 写代码 → 按 F5 → 编译运行
全程不需要 CMake。
1.2 但 VS 的项目文件是平台绑定的
VS 的项目文件(.sln/.vcxproj)只能在 Windows + VS 环境下使用:
┌─────────────────────────────────────────────────────────┐ │ VS 项目文件的局限性 │ ├─────────────────────────────────────────────────────────┤ │ │ │ MyProject.sln / MyProject.vcxproj │ │ │ │ │ ▼ │ │ 只能在 Windows + Visual Studio 下打开和编译 │ │ │ │ ❌ Linux 上无法使用 │ │ ❌ macOS 上无法使用 │ │ ❌ CI/CD 服务器上不方便(通常用 Linux) │ │ ❌ 其他 IDE(CLion、Qt Creator)无法打开 │ │ │ └─────────────────────────────────────────────────────────┘1.3 CMake 解决跨平台问题
┌─────────────────────────────────────────────────────────┐ │ CMake 的跨平台能力 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 一份 CMakeLists.txt │ │ │ │ │ ├──► Windows + VS → 生成 .sln → 编译 │ │ ├──► Linux + GCC → 生成 Makefile → 编译 │ │ ├──► macOS + Clang → 生成 Makefile → 编译 │ │ └──► CI/CD (Linux) → 生成 Makefile → 编译 │ │ │ │ 同一份代码,同一份配置,所有平台都能编译! │ │ │ └─────────────────────────────────────────────────────────┘1.4 实际场景
场景:团队协作 ───────────────── 小明用 Windows + VS 开发 小李用 Linux + VSCode 开发 CI 服务器用 Linux 自动编译 没有 CMake: 小明维护 .sln 文件 小李维护 Makefile CI 服务器再维护一套 Makefile 三套配置,改一个要同步三个 → 灾难! 有了 CMake: 所有人共用一份 CMakeLists.txt 改一次,所有平台生效 → 省心!2. VS 和 CMake 的关系
2.1 核心关系:CMake 是"图纸",VS 是"施工队"
┌─────────────────────────────────────────────────────────┐ │ CMake 和 VS 的关系 │ ├─────────────────────────────────────────────────────────┤ │ │ │ CMake = 建筑设计师(出图纸) │ │ ───────────────────────── │ │ - 画图纸(CMakeLists.txt) │ │ - 图纸可以给任何施工队用 │ │ │ │ VS = 施工队(按图纸施工) │ │ ───────────────────── │ │ - 拿到图纸(.sln 文件) │ │ - 按图纸施工(编译代码) │ │ - 但只能按自己的格式施工(只能读 .sln) │ │ │ │ CMake 的作用:把通用图纸翻译成 VS 能看懂的施工图 │ │ ───────────────────────────────────────── │ │ CMakeLists.txt ──► CMake 翻译 ──► .sln 文件 │ │ │ └─────────────────────────────────────────────────────────┘2.2 分工明确
┌─────────────────────────────────────────────────────────┐ │ 分工对比 │ ├──────────────────┬──────────────────────────────────────┤ │ CMake 做的 │ VS 做的 │ ├──────────────────┼──────────────────────────────────────┤ │ 读取 CMakeLists.txt│ 读取 .sln 文件 │ │ 检测编译器 │ 调用 MSVC 编译器 │ │ 查找依赖库 │ 编译 .cpp → .obj │ │ 设置编译选项 │ 链接 .obj → .exe │ │ 生成 .sln 文件 │ 提供调试功能 │ │ ❌ 不编译代码 │ ❌ 不生成 .sln(需要 CMake) │ └──────────────────┴──────────────────────────────────────┘2.3 两种关系模式
┌─────────────────────────────────────────────────────────┐ │ VS 和 CMake 的两种协作模式 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 模式一:CMake 在 VS 内部(VS 2019+) │ │ ───────────────────────────── │ │ VS 内置 CMake 支持 │ │ 用户打开 CMakeLists.txt → VS 自动调用 CMake → 编译 │ │ 用户感知不到 CMake 的存在 │ │ │ │ 模式二:CMake 在 VS 外部(传统方式) │ │ ───────────────────────────── │ │ 用户手动运行 CMake → 生成 .sln → VS 打开 .sln → 编译 │ │ CMake 和 VS 是独立的两个步骤 │ │ │ └─────────────────────────────────────────────────────────┘2.4 一句话总结
CMake 负责"生成构建文件",VS 负责"编译代码"。
CMake 不依赖 VS,VS 也不依赖 CMake。但两者结合,可以让你在 Windows 上享受 VS 的强大功能,同时保持项目的跨平台能力。
3. Visual Studio 使用 CMake 的两种方式
在 Windows 上使用 CMake 开发 VS 项目,主要有两种方式:
┌─────────────────────────────────────────────────────────┐ │ VS 使用 CMake 的两种方式 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 方式一:VS 直接打开 CMake 项目 │ │ ───────────────────────────── │ │ CMakeLists.txt ──► VS 自动检测并配置 ──► 编译运行 │ │ (VS 内部管理 CMake,无需手动操作) │ │ │ │ 方式二:命令行生成 .sln,再用 VS 打开 │ │ ───────────────────────────── │ │ cmake -B build -G "Visual Studio 17 2022" │ │ ↓ │ │ 生成 build/MyProject.sln │ │ ↓ │ │ VS 打开 .sln → 编译 │ │ │ └─────────────────────────────────────────────────────────┘4. 方式一:VS 直接打开 CMake 项目
4.1 工作流程
这是VS 2019 及以后版本推荐的方式,VS 原生支持 CMake。
┌─────────────────────────────────────────────────────────┐ │ VS 直接打开 CMake 项目 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 1. 打开 VS → 文件 → 打开 → 文件夹 │ │ │ │ │ ▼ │ │ 2. 选择包含 CMakeLists.txt 的文件夹 │ │ │ │ │ ▼ │ │ 3. VS 自动检测 CMakeLists.txt │ │ │ │ │ ▼ │ │ 4. VS 自动运行 CMake 配置 │ │ │ │ │ ▼ │ │ 5. 按 F5 直接编译运行 │ │ │ └─────────────────────────────────────────────────────────┘4.2 优点
- 无需手动操作:VS 自动处理 CMake 配置
- 配置简单:打开文件夹即可
- VS 集成好:IntelliSense、调试、断点全部可用
4.3 缺点
- 需要 VS 2019+:旧版本不支持
- 配置项较少:VS 的 CMake 配置界面功能有限
4.4 示例
# 1. 项目结构MyProject/ ├── CMakeLists.txt ├── src/ │ ├── main.cpp │ └── hello.cpp# 2. 打开 VS# 文件 → 打开 → 文件夹 → 选择 MyProject# 3. VS 自动配置并显示 CMake 输出# 输出窗口会显示:# CMake generation started.# CMake generation finished successfully.5. 方式二:命令行生成 .sln,再用 VS 打开
5.1 工作流程
这是传统方式,通过命令行生成 VS 项目文件,再用 VS 打开。
┌─────────────────────────────────────────────────────────┐ │ 命令行生成 .sln,再用 VS 打开 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 1. 打开命令行(CMD 或 PowerShell) │ │ │ │ │ ▼ │ │ 2. 运行 cmake 生成 .sln │ │ cmake -B build -G "Visual Studio 17 2022" │ │ │ │ │ ▼ │ │ 3. CMake 生成 build/MyProject.sln │ │ │ │ │ ▼ │ │ 4. 用 VS 打开 .sln 文件 │ │ │ │ │ ▼ │ │ 5. 在 VS 中编译、调试、运行 │ │ │ └─────────────────────────────────────────────────────────┘5.2 生成 .sln 的命令
# 指定 VS 版本(需要 VS 已安装)cmake-Bbuild-G"Visual Studio 17 2022"cmake-Bbuild-G"Visual Studio 16 2019"cmake-Bbuild-G"Visual Studio 15 2017"# 不指定 -G,CMake 自动选择最佳生成器cmake-Bbuild5.3 生成的目录结构
MyProject/ ├── CMakeLists.txt ├── src/ │ ├── main.cpp │ └── hello.cpp └── build/ ├── MyProject.sln ← 解决方案文件 ├── MyProject.vcxproj ← 项目文件 ├── CMakeCache.txt ← CMake 缓存 └── CMakeFiles/ ← CMake 中间文件5.4 优点
- 兼容所有 VS 版本:包括旧版本
- 完全控制:可以指定生成器、配置选项
- 适合 CI/CD:命令行操作,可自动化
5.5 缺点
- 需要手动运行命令行:多一步操作
- .sln 是自动生成的:修改 CMakeLists.txt 后需要重新生成
6. 配置阶段 vs 编译阶段
6.1 核心概念
┌─────────────────────────────────────────────────────────┐ │ CMake 的两个阶段 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 阶段一:配置阶段(Configuration) │ │ ───────────────────────────── │ │ 输入:CMakeLists.txt + 环境信息 │ │ 做什么: │ │ - 读取 CMakeLists.txt │ │ - 检测编译器、库、依赖 │ │ - 解析所有配置指令 │ │ - 生成 .sln / Makefile 等构建文件 │ │ 输出:构建文件(.sln / Makefile / .ninja) │ │ CMake 参与:✅ 这是 CMake 的工作 │ │ │ │ 阶段二:编译阶段(Build) │ │ ───────────────────────────── │ │ 输入:构建文件 + 源代码 │ │ 做什么: │ │ - 读取构建文件中的指令 │ │ - 调用编译器(MSVC)编译源代码 │ │ - 链接生成可执行文件 │ │ 输出:可执行文件(.exe) │ │ CMake 参与:❌ 完全不参与,这是 VS/MSBuild 的工作 │ │ │ └─────────────────────────────────────────────────────────┘6.2 关键认知:编译阶段与 CMake 无关
这是最重要的认知:
┌─────────────────────────────────────────────────────────┐ │ 编译阶段,CMake 完全不参与! │ ├─────────────────────────────────────────────────────────┤ │ │ │ 当你点击"生成"或运行 cmake --build 时: │ │ │ │ ❌ CMake 不会被调用 │ │ ❌ CMakeLists.txt 不会被读取 │ │ ❌ CMake 不知道你在编译什么 │ │ │ │ ✅ VS 调用 MSBuild │ │ ✅ MSBuild 读取 .sln 文件 │ │ ✅ MSBuild 调用 MSVC 编译器 │ │ ✅ MSVC 编译 .cpp → .obj → 链接 → .exe │ │ │ │ 整个编译过程,CMake 完全不在场! │ │ │ └─────────────────────────────────────────────────────────┘6.3 在 VS 中如何体现
┌─────────────────────────────────────────────────────────┐ │ VS 中的配置和编译 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 方式一(VS 直接打开 CMake): │ │ ───────────────────────── │ │ 打开文件夹 → VS 自动配置 → 按 F5 编译 │ │ ↓ ↓ ↓ │ │ 检测到 CMakeLists.txt 运行 CMake 配置 编译源代码 │ │ (CMake 参与) (CMake 不参与) │ │ │ │ 方式二(命令行生成 .sln): │ │ ───────────────────────── │ │ cmake → 生成 .sln → VS 打开 → 编译 │ │ ↓ ↓ ↓ ↓ │ │ 配置阶段 生成构建文件 加载项目 编译源代码 │ │ (CMake) (VS) (CMake 不参与) │ │ │ └─────────────────────────────────────────────────────────┘6.4 配置阶段做了什么
# CMakeLists.txt 中的配置指令 cmake_minimum_required(VERSION 3.10) project(MyProject VERSION 1.0.0) # 这些指令在配置阶段执行 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(MyApp src/main.cpp) # 配置阶段结束时,生成 .sln 文件 # .sln 文件描述了:编译哪些文件、用什么选项、怎么链接6.5 编译阶段做了什么
# 编译阶段执行的实际命令(以 MSVC 为例)# 这些命令由 MSBuild 自动调用,与 CMake 无关cl.exe /c /std:c++17 /EHsc /Iinclude src\main.cpp link.exe main.obj /OUT:MyApp.exe7. 什么时候需要重新生成 .sln
7.1 需要重新生成的情况
┌─────────────────────────────────────────────────────────┐ │ 什么时候需要重新生成 .sln │ ├─────────────────────────────────────────────────────────┤ │ │ │ 1. 修改了 CMakeLists.txt │ │ ───────────────────── │ │ - 添加/删除源文件 │ │ - 添加/删除库 │ │ - 修改编译选项 │ │ - 修改项目配置 │ │ │ │ 2. 新增了源文件(使用 file(GLOB) 时) │ │ ───────────────────── │ │ - 新增 .cpp/.h 文件 │ │ - 但使用 CONFIGURE_DEPENDS 时自动处理 │ │ │ │ 3. 更换了编译器或工具链 │ │ ───────────────────── │ │ - 从 MSVC 换成 MinGW │ │ - 更换 VS 版本 │ │ │ │ 4. 修改了 CMake 缓存变量 │ │ ───────────────────── │ │ - 修改 CMAKE_BUILD_TYPE │ │ - 修改 CMAKE_PREFIX_PATH │ │ │ └─────────────────────────────────────────────────────────┘7.2 不需要重新生成的情况
┌─────────────────────────────────────────────────────────┐ │ 什么时候不需要重新生成 .sln │ ├─────────────────────────────────────────────────────────┤ │ │ │ 1. 只修改了源代码(.cpp/.h) │ │ ───────────────────── │ │ - 修改函数实现 │ │ - 修改变量值 │ │ - 修改注释 │ │ - 原因:.sln 里记录的是"编译哪些文件",不是文件内容 │ │ │ │ 2. 只切换 Debug/Release 配置 │ │ ───────────────────── │ │ - VS 中直接切换构建类型 │ │ - 不需要重新运行 CMake │ │ │ │ 3. 只修改了代码逻辑 │ │ ───────────────────── │ │ - 优化算法 │ │ - 修复 bug │ │ │ └─────────────────────────────────────────────────────────┘7.3 实际演示
# 初始配置cmake-Bbuild-G"Visual Studio 17 2022"# 情况1:修改 CMakeLists.txt(添加新源文件)# 修改 CMakeLists.txt → 需要重新配置cmake-Bbuild# 重新生成 .sln# 情况2:只修改 main.cpp 中的代码# 不需要重新配置,直接编译cmake--buildbuild# 此时 CMake 完全不参与,MSBuild 直接编译# 情况3:修改 CMakeLists.txt 中的编译选项# 需要重新配置cmake-Bbuild# 重新生成# 情况4:切换 Debug/Release# 不需要重新配置cmake--buildbuild--configRelease8. VS 的 CMake 集成机制
8.1 VS 如何检测 CMake 项目
┌─────────────────────────────────────────────────────────┐ │ VS 检测 CMake 项目的机制 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 1. VS 扫描文件夹,寻找 CMakeLists.txt │ │ │ │ │ ▼ │ │ 2. 找到后,VS 自动创建 CMakeSettings.json │ │ │ │ │ ▼ │ │ 3. VS 根据配置运行 CMake │ │ │ │ │ ▼ │ │ 4. VS 读取 CMake 输出,获取项目信息 │ │ │ │ │ ▼ │ │ 5. VS 显示项目结构,提供 IntelliSense │ │ │ └─────────────────────────────────────────────────────────┘8.2 CMakeSettings.json(VS 专用配置文件)
{"configurations":[{"name":"x64-Debug","generator":"Visual Studio 17 2022","configurationType":"Debug","buildRoot":"${projectDir}\\out\\build\\${name}","installRoot":"${projectDir}\\out\\install\\${name}","cmakeCommandArgs":"","buildCommandArgs":"","ctestCommandArgs":"","inheritEnvironments":["msvc_x64"]},{"name":"x64-Release","generator":"Visual Studio 17 2022","configurationType":"Release","buildRoot":"${projectDir}\\out\\build\\${name}","installRoot":"${projectDir}\\out\\install\\${name}","cmakeCommandArgs":"","buildCommandArgs":"","ctestCommandArgs":"","inheritEnvironments":["msvc_x64"]}]}8.3 VS 的 CMake 输出
当 VS 配置 CMake 项目时,输出窗口会显示:
1> CMake generation started for configuration: x64-Debug. 1> Command line: "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -S "D:\MyProject" -B "D:\MyProject\out\build\x64-Debug" -G "Visual Studio 17 2022" -A x64 -DCMAKE_CONFIGURATION_TYPES=Debug 1> -- The CXX compiler identification is MSVC 19.35.0 1> -- Detecting CXX compiler ABI info 1> -- Detecting CXX compiler ABI info - done 1> -- Check for working CXX compiler: ... - works 1> -- Configuring done 1> -- Generating done 1> -- Build files have been written to: D:/MyProject/out/build/x64-Debug 1> CMake generation finished.8.4 VS 中的 CMake 操作
┌─────────────────────────────────────────────────────────┐ │ VS 中的 CMake 操作 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 菜单栏: │ │ ──────── │ │ 项目 → CMake 配置 │ │ 项目 → CMake 缓存 → 删除缓存 │ │ 项目 → CMake 缓存 → 重新生成 │ │ │ │ 工具栏: │ │ ──────── │ │ [x64-Debug ▼] [▶ 启动] [全部生成] │ │ │ │ │ └─ 切换配置、启动调试、编译 │ │ │ │ 右键菜单: │ │ ──────── │ │ 右键 CMakeLists.txt → │ │ - 重新配置 CMake │ │ - 打开 CMake 设置 │ │ - 在终端中打开 │ │ │ └─────────────────────────────────────────────────────────┘9. 两种方式对比与选择
9.1 对比表格
| 特性 | 方式一:VS 直接打开 CMake | 方式二:命令行生成 .sln + VS 打开 |
|---|---|---|
| 操作步骤 | 打开文件夹即可 | 命令行 + 打开 .sln |
| 跨平台 | ✅ 一份 CMakeLists.txt | ✅ 一份 CMakeLists.txt |
| 需要 VS 2019+ | ✅ | ✅(任一 VS 版本均可,但推荐新版) |
| 需要 CMake | ✅ | ✅ |
| 适合 CI/CD | ✅ | ✅(命令行更易自动化) |
| 适合场景 | 新项目、快速开发 | 需要精细控制、CI/CD |
9.2 选择建议
┌─────────────────────────────────────────────────────────┐ │ 如何选择? │ ├─────────────────────────────────────────────────────────┤ │ │ │ 如果你是: │ │ ────────── │ │ • VS 2019/2022 用户,想快速开始 │ │ → 方式一:VS 直接打开 CMake 项目 │ │ │ │ • 需要精细控制构建过程,或使用 CI/CD │ │ → 方式二:命令行生成 .sln,再用 VS 打开 │ │ │ │ • 团队协作,需要统一的构建配置 │ │ → 方式一/二:通过 CMakeLists.txt 统一管理 │ │ │ └─────────────────────────────────────────────────────────┘10. 总结与下一步
10.1 本篇核心要点
- ✅VS 本身不需要 CMake,但 CMake 让项目跨平台
- ✅CMake 是"图纸",VS 是"施工队",分工明确
- ✅方式一:VS 直接打开 CMake 项目,自动配置,适合快速开发
- ✅方式二:命令行生成 .sln,再用 VS 打开,适合 CI/CD
- ✅配置阶段:CMake 参与,生成 .sln
- ✅编译阶段:CMake 完全不参与,VS/MSBuild 独立工作
- ✅重新生成 .sln:修改 CMakeLists.txt 或新增文件时需要
- ✅VS 集成:CMakeSettings.json 控制 VS 的 CMake 配置
10.2 常见问题
Q1:修改 CMakeLists.txt 后,VS 会自动重新配置吗?
- 方式一:会自动检测并重新配置
- 方式二:需要手动重新运行 cmake
Q2:可以在 VS 中修改 CMakeLists.txt 吗?
- 可以,VS 支持编辑 CMakeLists.txt,且有语法高亮
Q3:生成的 .sln 文件可以手动修改吗?
- 可以,但下次运行 cmake 时会被覆盖
Q4:如何切换 Debug/Release?
- 方式一:VS 工具栏选择
- 方式二:VS 解决方案配置管理器
Q5:编译时 CMake 在做什么?
- 什么都不做!编译阶段 CMake 完全不参与,是 VS/MSBuild 在调用编译器。
10.3 下一步学习
你已经掌握了 CMake 与 VS 的协作机制,接下来可以:
👉阅读第四篇:[CMake 配置项详解],学习:
- 项目基本配置
- 编译选项配置
- 构建类型配置
- 路径配置
- 依赖库配置
💡 提示
建议你实际尝试两种方式,体验它们的区别。特别是方式一(VS 直接打开 CMake 项目),这是现代 VS 开发的最佳实践。
如果你在阅读过程中遇到问题,可以参考系列中的其他文档:
- 想复习 CMake 基础?→ 第一篇
- 想学习项目构建?→ 第二篇
- 想了解所有配置项?→ 第四篇
- 想深入学习语法?→ 第五篇