简介:面向64位Windows开发者的MinGW离线安装包,内部整合GCC 13.1.0稳定版,采用posix线程模型、seh异常处理与UCRT通用C运行时,可在不联网环境下直接搭建C/C++编译环境,适合需要在Windows上编译原生64位程序或进行跨平台开发的工程师和学习者。压缩包共18725个文件,约68.89MB,主要包含h/hpp头文件、a静态库、dll动态库、exe编译工具及Python辅助脚本等;头文件提供标准库与API声明,静态库和动态库支撑链接与运行,exe涵盖gcc/g++等核心程序,目录结构完整,解压后即可获得全套工具链。已有1647人学习/下载。相比在线安装器,这个离线包免去网络依赖,安装更高效,同时GCC 13.1.0带来更新的语言标准支持与优化能力,帮助开发者在64位环境下顺利构建高性能原生应用。
1. MinGW-w64 64位离线安装包:解压即用,但解压前得先看懂几个英文后缀
MinGW-w64 64位离线安装包这两年基本成了 Windows 上 C/C++ 开发的默认起点,可下载页面上那串 x86-64-13.1.0-release-posix-seh-ucrt-rt-v11-r 英文后缀,劝退过不少人。我见过不止一个开发者把 posix 当成操作系统,把 seh 当成乱码,解压完草草配个 PATH 就开始写代码,结果要么编译出来的 exe 在别人电脑上缺 dll,要么一开 std::thread 就 link error。这套版本号里每个字段都是二选一或三选一,选错了,后面所有时间都得花在跟环境搏斗上。
MinGW-w64 13.1.0 这套离线包的优势很干脆:不要安装器、不依赖在线下载、解压即用。对离线环境、内网部署、CI 构建镜像和机房这类不方便联网拉包的地方,release 形态的离线包是最省心的工具链分发方式。这篇笔记按我自己的装机顺序来写:先拆版本号把每个字段读明白,再走下载、解压、配置环境变量,附上五条高频报错排查,最后给一套两分钟能跑完的验证流程。新手照着走能一次配通,熟手可以直接跳到第五、六章捡排错思路。
2. 版本选型:x86-64、posix、seh、ucrt 四个后缀决定你编不编得过
2.1 逐段拆解版本号:13.1.0、release 和 rt-v11-r 分别是什么
先把这个版本的完整标识拆开看,每一段都是独立的决策点。x86-64 是目标架构,代表这套工具链编译出来的是 64 位 PE 程序,只能在 64 位 Windows 上运行。如果你将来要把程序发布给还在用老 32 位机器的用户,那得另找一套 32 位工具链,但手上这个包本身就是 x86-64 定位,架构选择没有悬念。
13.1.0 是 GCC 版本号,GCC 13 系列的正式发布版。对这个版本来说,C++20 标准库支持已经比较完整,像 std::format 这类实用库组件可以直接用,C++23 的核心语言特性也基本齐了,对绝大多数项目来说够新也够稳,不需要再去追更新的编译器。release 表示这是正式构建而非 nightly 或 snapshot 测试版,日常使用选 release 即可。
rt-v11-r 是配套运行库的版本编号,v11 是这一轮发布的 runtime 版本,r 是 revision 修订号,与 GCC 13.1.0 的配套组件绑定在一起。这个字段平时写代码用不到,但向别人报告版本信息、反馈工具链问题时,带上完整标识能让对方一眼判断你的组件配套关系。
2.2 线程模型:posix 还是 win32
MinGW-w64 的 GCC 分两套线程模型:posix 和 win32。这里的 posix 不是说你的程序跑在 Linux 上,而是说编译器内部用 POSIX 线程语义来提供 C++11 开始的标准线程库支持。选 posix 模型,编出来的程序可以使用 std::thread、std::mutex、std::condition_variable 这些标准库并发设施,底层由 winpthread 库通过 Win32 线程 API 实现。
选 win32 模型则不同,GCC 不提供完整的 pthread 语义,C++ 标准线程在 libstdc++ 里的支持被裁剪,写多线程代码很容易踩到编译错误或行为不一致。排查的时候你会发现代码没问题,其实是编译器模型选错了。我的结论很简单:你现在写的是 C++,十有八九要开线程,选 posix 不会多付出任何学习成本,唯一代价是动态链接时多一个 libwinpthread-1.dll 运行时依赖,这个第五、六章都会提到。
| 线程模型 | 底层实现 | 典型适用 |
|---|---|---|
| posix | winpthread 封装 Win32 线程 API,提供 POSIX 语义 | std::thread、std::mutex、std::async 等 C++ 并发代码 |
| win32 | 直接映射 Win32 线程 API,无完整 pthread 语义 | 纯 C 项目、不使用标准线程库的旧代码 |
2.3 异常处理模型:seh、sjlj、dwarf 的取舍
异常处理模型决定 C++ 的 throw 和 catch 在二进制层面如何实现。dwarf 是 32 位工具链才有的方案,64 位下不用考虑。64 位环境只有两个实际选择:seh 和 sjlj。seh 使用 x64 平台自带的硬件异常处理机制,运行时开销趋近于零,生成代码也更紧凑,缺点是它只能用于 64 位。
sjlj 基于 setjmp/longjmp 实现,跨平台兼容性最好,但每次进入 try 块都要保存恢复点,性能损耗明显。这个包定位就是 x86-64,所以 seh 是当然之选,不需要犹豫。编译器本身对这两种模型的支持取决于构建时配置,如果哪天你在链接阶段看到跟异常处理相关的诡异报错,第一反应应该是检查工具链构建配置,而不是去改代码。
2.4 C 运行库:ucrt 凭什么成为主流
C 运行库选项上,新版构建基本就是 ucrt 和 msvcrt 二选一。msvcrt 是 Windows 95 时代的老运行库,连 C99 支持都不完整,现在只有在维护极老的项目兼容性时还会被人提起。标题里的 ucrt 是 Windows 10 及以上系统内置的 Universal C Runtime,C99 支持完整,还带了部分 C11 特性。
对现代 C/C++ 项目来说,ucrt 是默认正解。它最大的好处是编出来的程序在 Win10/11 上不需要额外携带运行库,系统自带。要注意的是 ucrt 工具链产物在 Windows 7 上需要先装系统补丁才能跑,如果你要发布到老系统环境,这一点提前规划好。现在从 MinGW-w64 官方构建渠道下载的 64 位包基本都做了 ucrt 默认化,老教程里教人选 msvcrt 的做法已经不适用了。
这一章读下来,结论其实很集中:64 位 + posix 线程模型 + seh 异常处理 + ucrt 运行库,就是当前 Windows 下 C/C++ 开发最主流的一套配置组合,也就是标题这一套。
3. 下载与解压部署:离线包到手后的三步操作
3.1 下载与校验:先确认文件完整性,再谈解压
MinGW-w64 的发行版形态和别的工具链不一样,它不提供安装向导,发布物就是一个 7z 压缩包,解压即用。进入官方构建发布页面后,找到 x86-64-13.1.0-release-posix-seh-ucrt-rt-v11-r 这个目录即可。目录里会同时提供 7z 压缩包和源码包,我们只需要 7z 那个,文件名里一般带着 posix-seh-ucrt 的完整标识,对照标题选就不会错。
下载完成后第一件事是校验,这一步很多人跳过,我不建议省。7z 包体积不小,网络中断或磁盘异常都可能导致压缩包损坏,而损坏的包往往要到解压中段才报错,这时候排查起来最费劲。我一般会先对着发布页上标注的文件大小核对字节数,有条件再对一下哈希值。这个动作花不到半分钟,能过滤掉一种非常玄学的解压报错。
解压时用 7-Zip 即可,命令行方式如下:
7z x x86_64-13.1.0-release-posix-seh-ucrt-rt-v11-r.7z -oC:\mingw64这里的-o参数指定解压输出目录,注意-o后面不带空格,直接跟上目标路径。选择C:\mingw64作为根目录是为了后面配置和排错时路径短、无空格、好记,具体原因下面马上展开。
3.2 解压路径选择:空格、长路径、多套一层目录三个坑
解压路径有三个讲究。第一,避免放进带空格的目录,比如C:\Program Files就不建议,部分老构建脚本对空格路径处理不好,会导致奇怪的找不到文件。第二,路径别太长,嵌套层级越多,越容易在某些构建工具里触发长路径问题,这也是我推荐浅目录的原因之一。第三,解压后的目录层级要确认清楚。
解压完成后,根目录下应该直接看到 bin、include、lib 这些子目录。如果你解压完发现 bin 目录不在根下,说明压缩包内容被多套了一层目录,通常是用 7-Zip 时输出目录参数写重复了。处理方式很简单:把多套出来的那一层直接移上来,或者重新解压一次,不要留着一个层级混乱的目录继续配置,不然后面写路径十有八九会写错。
正常解压后的目录结构大致是这样的:
C:\mingw64 ├── bin ├── include ├── lib ├── libexec ├── share └── x86_64-w64-mingw32bin 是编译器、汇编器、链接器等可执行文件的存放位置;include 存放 C/C++ 标准库头文件;lib 是链接器要搜索的静态库目录;x86_64-w64-mingw32 下面放的是目标平台特定的配套文件。理解这几个目录的职责,后面配置环境变量和排查头文件问题时就有方向了。
3.3 首次自检:bin 目录里该看到哪些可执行文件
配置环境变量之前,先进 bin 目录做一次目检。正常情况下应该能看到 gcc.exe、g++.exe、ar.exe、as.exe、ld.exe、nm.exe、objdump.exe、strip.exe 这些工具。两个常用的编译入口是 gcc.exe 和 g++.exe,前者编译 C,后者编译 C++。ar 和 strip 在后续做静态库和裁剪二进制时会用到,现在不用管。
| 可执行文件 | 职责 |
|---|---|
| gcc.exe | C 语言编译器驱动 |
| g++.exe | C++ 语言编译器驱动 |
| as.exe | 汇编器,把汇编代码转成目标文件 |
| ld.exe | 链接器,负责把所有目标文件拼成最终 exe |
| ar.exe | 静态库管理工具 |
| mingw32-make.exe | 构建驱动工具,对应 Linux 下的 make |
bin 目录里还会看到 libwinpthread-1.dll 和 libstdc++-6.dll 这类动态库文件,它们是 posix 模型和 C++ 标准库的运行时所在地。记住这些 dll 的位置,后面遇到 exe 在其他机器上"缺少 dll"的报错时,你会需要这个记忆。另外,官方发布包里默认只有 mingw32-make.exe,不会提供叫 make.exe 的文件,这跟 Linux 上的习惯不一样,习惯用 make 的同志先在心理上做个准备,第五章有专门一节讲这个。
4. 环境变量配置:PATH、INCLUDE、LIB 三处最容易写错的路径
4.1 PATH 配置:命令行方式与面板方式的取舍
PATH 是环境变量里最核心的一个,这章直接讨论写法。先说命令行的方式,在命令提示符里执行:
setx PATH "%PATH%;C:\mingw64\bin"setx 会把这行命令里的 PATH 值固化到用户级环境变量。不加/M参数只改当前用户,加/M则是写系统级变量但需要管理员权限。个人开发机用用户级就够了,不要动系统级,避免影响机器上其他账号。执行完 setx 之后,当前终端并不会立刻生效,必须新开一个终端窗口,这是新手第一个容易懵的点。
注意:setx 对 PATH 长度有上限限制,注册表里的 PATH 超过一定长度时 setx 可能写入失败。如果执行后提示错误,直接改用图形化的环境变量面板手动编辑。
这里有个 setx 特有的坑需要警惕:%PATH%会被展开成当前进程的完整 PATH 值,再拼上C:\mingw64\bin写回去。如果你的终端里临时加过其他路径,这些临时值会被一并固化到用户变量里,污染后续环境。我实际上更推荐在系统属性的环境变量面板里手工编辑 Path,新增一行C:\mingw64\bin然后确定,不经过任何拼接,逻辑最干净,也方便观察已有变量顺序。
4.2 INCLUDE 和 LIB:什么时候需要手动配
这一节容易被人带偏,网上很多教程让新手把C:\mingw64\include和C:\mingw64\lib也配进环境变量,其实对 MinGW-w64 来说这两项大多时候不配也能用。原因是 GCC 的内置头文件搜索路径在编译器内部已写死,不依赖 Windows 的 INCLUDE 环境变量。你在命令行里直接执行gcc test.cpp -o test.exe,标准库头文件照样能找到,这就是为什么很多人只配了 PATH 也能编译通过。
那 INCLUDE 和 LIB 什么时候真正起作用?主要是某些构建系统或 IDE 拿它们当搜索依据,比如 CMake 在少数配置模式下、部分老项目脚本里。全局设 INCLUDE 的风险是:如果配错了路径,或者机器里存在多套开发工具,编译器可能错误地优先去一个旧头文件目录,最终出现的头文件版本混乱问题会非常隐蔽。真正需要为项目添加头文件搜索路径时,正确做法是用编译器参数-I指定,而不是动全局环境变量。
g++ -I C:\myproject\include -L C:\myproject\lib main.cpp -o main.exe-I是头文件搜索路径,-L是链接库搜索路径。这两个参数只作用于当前编译命令,不会污染系统环境,排查问题时也更容易定位。全局环境变量能不用就不用,这是我配这么多年环境得出的一个习惯。
4.3 配置生效验证:新开终端三连查
环境变量配置完,建议按下面的顺序查一遍。第一步查 PATH 是否真的包含新路径:
echo %PATH%在输出里找到C:\mingw64\bin确认位置。第二步用 where 命令确认命令行解析到的是哪个 gcc:
where gcc where g++这一步主要防 PATH 里存在多个 gcc 的情况。如果 where 输出的不是C:\mingw64\bin\gcc.exe,说明系统里还有其他编译器命中更快,需要调整 PATH 顺序,把 MinGW 的 bin 放到前面。第三步查编译器内置搜索路径是否正常:
echo int main(){} | gcc -E -v -x c++ --E表示只做预处理不编译,-v输出详细过程,-x c++强制按 C++ 处理输入,最后的-表示从标准输入读取代码。输出末尾会列出编译器内置的 include 搜索路径,里面应该出现C:\mingw64\lib\gcc\x86_64-w64-mingw32\13.1.0\include\c++这样的路径。如果这里列出的是一堆 Linux 路径,不用怀疑,你调用到了别处移植的 gcc,回头检查 PATH。
5. 常见问题排查:五条高频安装踩坑记录
5.1 gcc 不是内部或外部命令
现象:新开终端后输入 gcc 或 g++,提示不是内部或外部命令。原因:PATH 里没有包含C:\mingw64\bin,或者 setx 写入后没有新开终端,旧终端里 PATH 没刷新。解决:先新开一个终端再试一次,仍不行就手动打开环境变量面板确认 Path 里的条目,确保没有拼错路径。如果 PATH 里确实有,但 where gcc 解析到了别的目录,说明其他工具链抢先命中,把C:\mingw64\bin上移到更靠前的位置。
5.2 编译出的 exe 在其他电脑上报缺少 libwinpthread-1.dll
现象:程序在自己机器上编译运行正常,拷贝给别人或换个目录双击,报找不到 libwinpthread-1.dll。原因:posix 线程模型下,C++ 程序的动态链接会依赖 libwinpthread-1.dll,启动时系统会按 exe 同目录和 PATH 顺序搜索这个 dll,目标机器上没有就报错。解决有两种,轻量做法是把 bin 目录里的那个 dll 复制到 exe 同级目录一并分发;更省心的做法是编译时直接静态链接:
g++ hello.cpp -o hello.exe -static-static会让 gcc 把 libgcc、libstdc++、libwinpthread 全部静态编进 exe,目标机器不需要任何额外 dll。代价是文件体积变大,但换来的是"拷过去就能跑"的确定性。我对外发布 Windows 程序时几乎都走-static,除非明确知道目标环境可控。
5.3 Linux 代码迁移过来头文件一片红
现象:在 Linux 上正常的 C++ 工程,拿到 Windows 下一编译就报fatal error: unistd.h: No such file or directory,随后 sys/socket.h、pthread.h 等一连串头文件跟着报错。原因:MinGW-w64 的目标平台是 Windows,不提供 POSIX 系统头文件,代码里写的是 Linux 系统编程接口而不是纯标准 C++。解决:必须在代码层做平台适配,把 unistd.h 相关调用包在#ifdef _WIN32分支里,Windows 侧使用_getcwd、_read等对应接口;pthread 线程代码优先改用std::thread,MinGW 的 posix 线程模型会接管底层实现。不要在编译器选项上找万能开关,没有这种东西。
5.4 机器里多套 GCC,CMake 认错编译器
现象:CMake 执行 configure 时说找不到 C 编译器,或者检测出来的编译器版本很旧,甚至报告目标平台是 32 位。原因:系统 PATH 里混着多个 GCC 发行版,可能是某个 IDE 自带的旧工具链,也可能是以前装过的另一个移植环境,CMake 按 PATH 顺序找到哪个就用哪个。解决:配置时显式指定编译器路径:
cmake -DCMAKE_C_COMPILER=C:/mingw64/bin/gcc.exe -DCMAKE_CXX_COMPILER=C:/mingw64/bin/g++.exe ..路径分隔符用正斜杠,避免反斜杠被解释成转义。如果项目已经配置过一次,建议先删掉 build 目录里的 CMakeCache.txt 再重新 configure,否则残留缓存可能继续引用旧编译器。
5.5 make 命令不存在,只有 mingw32-make
现象:照着项目文档敲make,第一行就提示不是内部或外部命令。原因:MinGW-w64 官方构建的可执行文件名是 mingw32-make.exe,刻意不带 make 这个名字,就是为了避免和系统里其他 make 撞名。解决:命令行里改用 mingw32-make 执行,Makefile 内容本身基本兼容,因为它是 GNU make 的移植版本。嫌名字长可以用 doskey 定义别名,只在当前终端有效:
doskey make=mingw32-make $*不建议在 bin 目录里硬造一个 make.exe 副本,将来如果再装其他工具链,同名冲突会让你再次陷入排查。用原名或终端别名,路径归属清晰,排查时一眼能看清。
6. 安装验证:编译出一个线程程序才算真的跑通
配置完成后,我每次装机都会强制走一遍下面这三步验证,任何一步不过就停下来排查,不把问题留到写项目时再暴露。
第一步确认编译器身份:
gcc --version gcc -dumpmachine第一行确认版本是 13.1.0,第二行-dumpmachine输出目标平台三元组,正确结果是x86_64-w64-mingw32。如果这里输出的是 i686 或别的架构标识,说明工具链选型有问题,立刻回溯到第二章。
第二步编译一个带线程的 C++ 程序,验证 posix 线程模型、标准库和静态链接三件事同时成立。
#include <iostream> #include <thread> int main() { std::thread t([] { std::cout << "mingw ok" << std::endl; }); t.join(); return 0; }编译命令:
g++ mingw_check.cpp -o mingw_check.exe -std=c++17 -static.join()表示主线程等待子线程结束。如果这一步报链接错误,基本可以断定线程模型选成了 win32,回到第二章换 posix 版本重装。-static同时验证静态链接完整,产物可以直接拷到干净机器上试跑。
第三步走一遍构建系统通道,写个最简单的 Makefile,用 mingw32-make 驱动:
mingw_check.exe: mingw_check.cpp g++ mingw_check.cpp -o mingw_check.exe -std=c++17 -static执行mingw32-make,看到生成 mingw_check.exe 且运行输出 "mingw ok",说明命令行、编译器、构建驱动三层链路全部打通。日常在 VS Code 里开发,装上 C/C++ 插件后,记得检查 c_cpp_properties.json 里的 compilerPath 是否指向C:/mingw64/bin/g++.exe,路径用正斜杠,插件会自动复用这套工具链完成编译和调试。
从那以后我每次配完 MinGW 都会强制走一遍这三步:先看 gcc --version 和 -dumpmachine,再编一个带线程的静态程序,最后跑一次 mingw32-make。这套流程加起来用不了两分钟,但能过滤掉八成后续开发期的环境问题。希望帮到你。
本文还有配套的精品资源,点击获取