0.2 Windows 上的 C++ 工具链
你在图形化 IDE 中点击「运行」时,背后至少发生了这些事情:编辑器保存源文件,编译器把源文件翻译成目标文件,链接器把目标文件和库组合起来,操作系统再启动生成的可执行文件。
这些环节都被 IDE 包办,所以刚开始写代码会很舒服。但当遇到找不到头文件、不支持新特性这类错误,就很难判断问题究竟出在哪里。而且,我们将在后续的第三章中详细介绍构建系统、CMake、测试和 CI,因此了解 IDE 实际如何工作是十分有必要的。
考虑到其实大多数初学者仍然使用的是 Windows 系统,使用 WSL 或迁移到 Linux 将会是不小的负担(尤其考虑在中国大陆地区还需要配置镜像或网络代理,会进一步增加复杂度
理解工具链角色
在动手之前我们先来了解我们使用的工具链各自承担什么角色。
GCC,GNU Compiler Collection,GNU 编译器集合,其中的 g++ 是 C++ 编译驱动程序。我们接下来主要使用它作为编译器。libstdc++ 是 GCC 生态中的 C++ 标准库实现,提供 <vector>、<string>、<span> 等头文件和库。
但要想生成 Windows 原生程序,则需要有一套工具链接 GCC 与 Windows API、C 运行库。在早期 MinGW(Minimalist GNU for Windows)承担了这个角色。但由于其功能受限、仅支持 32 位,后来又出现了 MinGW-w64 项目,是现在的主力。我们使用 #include <windows.h>、HWND、MessageBox 这些 Windows 接口时,依赖的就是它。
Clang 是另一款编译器,以 clang++ 作为驱动程序。我们这里暂时不用,后续详细介绍。
在 Windows 这边,系统也为 C / C++ 准备了运行时 —— C Runtime,缩写 CRT。在早期使用 MSVCRT(Microsoft Visual C Runtime
这一套配置十分复杂。因此便有一些简化的尝试。在 Dev-C++ 中内置的 TDM-GCC,便是一个第三方打包好的 GCC 工具链发行版。它包含了 GCC、MinGW-w64、binutils 和各种配置,整合在一个安装包里,方便用户安装使用。但 TDM - GCC 的最新正式 release 目前还是 GCC 10.3.0,发布时间已经比较久了,不太建议现在再使用。
现在一般推荐使用 MSYS2 进行配置。它是一个开发环境或者说软件生态,将 Bash、Autotools、Make、Git、GCC、GDB 等全部整合进来,为 Windows 提供一套「类似 Linux」的开发体验。它使用从 Arch Linux 移植过来的 pacman 作为包管理器,管理这些软件。
MSYS2 提供了若干「环境」以方便管理。所谓的「环境」规定了架构、编译器、运行时等,类似一张餐桌加一份菜谱,让 pacman 安装即可开始享用。需要注意:MSYS2 提供的几个环境的名字很有迷惑性:我们会看到 MSYS、MINGW64、UCRT64、CLANG64,它们是环境的名字,不是我们前面所说的工具!它们的大致配置如下:
| 环境 | 编译器 | 接口 | 运行时 | 架构 | 当前定位 |
|---|---|---|---|---|---|
| UCRT64 | GCC | MinGW-w64 | UCRT | x64 | 推荐 |
| MINGW64 | GCC | MinGW-w64 | MSVCRT | x64 | 旧环境 |
| CLANG64 | Clang | MinGW-w64 | UCRT | x64 | 可用 |
MSYS2 已在 2026 年开始弃用 MINGW64 环境,这里仍列出它,是因为旧教程和已有安装中经常能看到这个名字。新安装按官方建议选择 UCRT64 即可。
而 MSYS 环境比较特殊,它运行一个自己的 MSYS2 运行时,用来跑 Unix 世界的工具链,其中虽然也有 GCC 但它是用来编译 MSYS 程序的,其中没有 MinGW-w64,也不能用来编译原生 Windows 程序。
安装环境
我们刚才提到,接下来使用 GCC + MinGW-w64 + UCRT,对应 MSYS2 里的 UCRT64 环境。因此我们接下来要:安装 MSYS2、进入其中的 UCRT64 环境、使用 pacman 安装 GCC 等工具链。
从 MSYS2 官方网站 下载安装器。安装位置建议采用短的 ASCII 路径,例如默认的 C:\msys64。一路下一步之后点击完成。此时开始菜单里会出现 MSYS2 各个环境的快捷方式。打开 MSYS2 UCRT64(注意不是 MSYS2 MSYS
NOTE
如果你想在自己常用的终端软件中打开,启动它的命令行是:
C:\msys64\msys2_shell.cmd -defterm -here -no-start -ucrt64 -shell bash启动路径为:
C:\msys64\home\%USERNAME%如果你自定义了安装路径,需要把 C:\msys64\ 替换为你的安装路径。
打开后,你应该会看到形如:
linho@LinhosPC UCRT64 ~
$如果你对这样的界面不太熟悉,这里介绍一下:这是 bash 终端,开头的绿色是 用户名@计算机名,紫色的 UCRT64 是当前的环境名称,~ 是当前路径,当前位于 home 目录。$ 后可以输入命令,回车执行。
执行命令更新 MSYS2 本身:
pacman -Suy如果它提示关闭当前终端,确认后关闭窗口,再重新打开 MSYS2 UCRT64,继续执行一次 pacman -Suy。MSYS2 是滚动更新的发行版,官方建议初次打开时进行完整更新。
更新完成后,在 MSYS2 UCRT64 终端中执行:
pacman -S --needed mingw-w64-ucrt-x86_64-toolchain这个工具链组除了 GCC,还会安装 binutils、GDB、Make、Windows 头文件和运行库等组件。
此时,执行
g++ --version应该会看到形如这样的输出:
g++.exe (Rev3, Built by MSYS2 project) 16.2.0
Copyright (C) 2026 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.这表明 GCC 已经成功安装。
第一次从命令行编译
假设有一个 C++ 源文件 D:\cpp_playground\hello_world.cpp 需要编译。仍然在 MSYS2 UCRT64 终端中,进入目录(盘符 D:\ 使用 /d/ 表示
cd /d/cpp_playground然后执行:
g++ -std=c++20 -Wall -Wextra -Wpedantic hello_world.cpp -o hello_world.exe参数的含义是:
| 参数 | 作用 |
|---|---|
-std=c++20 | 使用 C++20 语言模式 |
-Wall | 开启一组常见警告 |
-Wextra | 开启更多额外警告 |
-Wpedantic | 对偏离标准的写法给出提示 |
-o hello_world.exe | 指定输出文件名 |
接下来执行
./hello_world.exe即可启动你的程序。
这就是 IDE 的「编译并运行」按钮最终会调用的某种命令。IDE 可以继续使用,但现在你知道如何绕过它独立验证工具链了。
在其他地方调用
开发工具链本质上还是一堆文件。要从其他地方启动它,则还需要一些配置。在刚才的终端中执行:
where.exe g++会得到形如 C:\msys64\ucrt64\bin\g++.exe 的路径,这便是 g++ 所在的位置。
如果你只想在 PowerShell 中直接调用 g++,可以考虑将该目录添加到 PATH。不过,MSYS2 环境还会设置 MSYSTEM、MINGW_PREFIX 等变量,部分工具不能仅靠添加一个目录完整复现环境。更稳妥的做法是在终端或 IDE 中配置 MSYS2 UCRT64 shell;只调用原生的 g++.exe 时再使用 PATH。
你也可以设置现有的 IDE,使其指向刚才安装的 GCC。
以常用的教学工具 Dev-C++(或者它的修改版,例如小熊猫 C++)为例:
- 进入 选项 → 编译器 → 配置集,在「编译器配置方案」下拉框的右侧有一个文件夹按钮,点击选择上面的目录,即可自动识别到 GCC 并使用;
- 在对话框下方的 编译 / 链接选项 → 代码生成 中,可以选择 C++ 语言标准为「ISO C++20
」 ; - 在对话框下方的 编译 / 链接选项 → 代码警告 中,勾选「启用常见问题警告 (-Wall)」和「启用更多问题警告 (-Wextra)
」 。
此时编译文件,底部的「工具输出」栏显示:
编译单个文件...
------------------
- 文件名: D:/cpp_playground/hello_world.cpp
- 编译器配置: MinGW-w64 GCC 16.1.0 64-bit Debug
正在处理C++源程序文件:
------------------
C++编译器: C:/msys64/ucrt64/bin/g++.exe
命令: g++.exe D:\cpp_playground\hello_world.cpp -o D:\cpp_playground\hello_world.exe -g3 -fno-ms-extensions -std=c++2a -pipe -Wall -Wextra -Werror=return-type -Werror=vla -D_DEBUG -Wl,--stack,12582912
编译结果:
------------------
- 错误数: 0
- 警告数: 0
- 输出文件名: D:\cpp_playground\hello_world.exe
- 输出文件大小: 400.24 KiB
- 编译时间: 0.47 秒可以看到编译时调用的便是刚才配置的 GCC 了,也可以看到其实际调用的命令行。
这里的 C++ 标准选项写的是
-std=c++2a。这是 C++20 在标准正式定稿前使用的临时名称,后来 GCC 将正式名称改为-std=c++20,同时保留了c++2a作为兼容别名。