简介:面向Windows平台C/C++开发者的MinGW mingw64完整配置包,适合刚接触GNU工具链、需要快速搭建本地编译环境的初学者。压缩包共2000个文件,约129.46MB,以h/hpp头文件和Python脚本为主,另有c源码、txt说明、shell脚本与doc文档,基本覆盖GCC编译运行所依赖的库文件与辅助工具。已有3796人学习下载。相比官方在线安装器需要手动勾选组件、配置PATH,该完整包解压后设置环境变量即可投入编译使用,省去逐项下载的麻烦;内含的头文件、构建脚本与说明文档,也有助于理解MinGW64目录结构、排查配置问题,是Windows下启动C/C++开发的高性价比资源。
1. Windows 上配 MinGW 为什么容易翻车:先分清三个名字再说
花半小时下了一个 MinGW 完整包,解压后照着教程加好环境变量,敲 gcc --version 却提示「不是内部或外部命令」——这种翻车我修过太多次了,十有八九是下到的和你要装的并不是同一个东西。MinGW 是 GCC 编译器在 Windows 上的移植版,而大家真正在用的其实是它的 64 位后继项目 MinGW-w64。这份完整包把编译器本体、头文件、库、gdb 和 mingw32-make 打包在一个目录里,解压、配一条 PATH、编译第一个 hello.exe,半小时内能把整条工具链跑通。适合在 Windows 上写 C/C++ 但不想被 Visual Studio 拖住的开发者,也适合从 Linux 切到 Windows 临时编译开源库的人。
2. 选型篇:MinGW-w64、MSVC 与「完整包」到底选哪个
2.1 还在下 MinGW 官网?那个项目早就停更了
很多人搜「mingw 官网下载」,点进去看到的页面其实还挂在 SourceForge 或者 OSDN 上,项目名写着 MinGW,安装工具叫 mingw-get。这个项目是 2000 年前后启动的,目标是让 GCC 能在 Windows 上跑起来,但它的主分支长期停留在 32 位,更新频率很低。装 mingw-get 的过程中要在线拉一堆组件包,网络一波动就卡在某个「downloading gcc-core」的进度条上,最后装出来只有 gcc 没有 gdb 的情况很常见。更尴尬的是这个在线安装器把编译器拆成几十个组件,新手根本分不清哪些是必选,装完一编译报缺头文件,心态直接炸。
真正在社区里被广泛使用的是 MinGW-w64,这是后来的一个分叉,目标明确:支持 64 位目标、适配新的 Windows 运行时。你现在在各类课程资料、开源项目说明里看到的「MinGW」,几乎都是指这一系。因为历史原因,它的官网域名还叫 mingw-w64.org,下载入口散落在 SourceForge 和各家打包发行版。怎么区分一个包是老 MinGW 还是 MinGW-w64,看 bin 目录下的可执行文件名就行:老项目叫 mingw32-gcc.exe,MinGW-w64 系叫 x86_64-w64-mingw32-gcc.exe(64 位)或 i686-w64-mingw32-gcc.exe(32 位)。文件名里带 w64 字样的,放心用。
| 项目 | 老 MinGW | MinGW-w64 |
|---|---|---|
| 定位 | GCC 的 Windows 初期移植 | 支持 64 位的后继分叉 |
| 可执行文件命名 | mingw32-gcc.exe | x86_64-w64-mingw32-gcc.exe / i686-w64-mingw32-gcc.exe |
| 目标架构 | 32 位为主 | 32 / 64 位 |
| 维护状态 | 长期停滞 | 活跃,多个发行版并存 |
「mingw 官网下载」这组词现在搜出来,前排也大多是 MinGW-w64 相关的资源站点,老官网只是被搜索引擎保留了权重。看到页面风格停留在 2005 年前后、下载按钮指向 mingw-get 的,留个心眼:那不是你要的完整包,是历史遗留物。
2.2 MSVC 与 MinGW-w64 的本质差异:运行时、ABI 与构建工具
决定用 MSVC 还是 MinGW-w64,其实是在选「运行依赖」和「工具链习惯」。MSVC 是 Visual Studio 自带的编译器,编出来的程序依赖 VC 运行库 vcruntime140.dll、msvcp140.dll;MinGW-w64 用的是 GCC,支持两种 C 运行时:MSVCRT 和 UCRT。MSVCRT 是 Windows 95 时代就跟着系统走的 C 运行库,Win10 之前的系统全带,但功能停留在很老的 C 标准;UCRT 是 Windows 10 引入的通用 C 运行库,Visual Studio 2015 之后也在用,C99/C11 的函数支持明显更全。现在新发布的 MinGW-w64 发行版大多默认走 UCRT,选包时认准 ucrt 字样。
ABI 层面两者完全不相通:MSVC 和 GCC 的 C++ 符号修饰规则不同,异常处理模型也不同。MSVC 用自己的异常处理机制,MinGW-w64 在 x64 下用 SEH。所以你没法把一个 VS 编出来的静态库直接丢给 gcc 链接,反之也一样。项目里碰到 .lib 文件时先确认它是 MSVC 格式还是 MinGW 格式,混用会报一堆 unresolved symbol,这属于两个生态之间最经典的「黑匣子」问题。
构建工具也不一样:MSVC 生态里是 MSBuild 和 nmake,MinGW 生态里是 mingw32-make,和 GNU make 同源,特意改名是为了避免和其它 make 冲突。调试器对应关系更直接:MSVC 用 VS 自带调试器读 PDB 格式信息,MinGW 用 gdb 读 DWARF 格式信息。Eclipse CDT、VS Code 的 C/C++ 插件都能接 gdb,这也是 GNU 工具链在编辑器生态里顺滑的原因。
| 维度 | MSVC | MinGW-w64 |
|---|---|---|
| 编译器命令 | cl.exe | gcc.exe / g++.exe |
| C 运行时 | UCRT(VS2015 之后) | MSVCRT 或 UCRT |
| C++ 标准库 | Microsoft STL | libstdc++(GCC 自带) |
| Make 工具 | nmake / MSBuild | mingw32-make |
| 调试器 | VS Debugger(PDB) | gdb(DWARF) |
| 许可证 | 专有 | GPL 系 |
| 典型场景 | Windows 桌面应用、商业闭源 | 开源库、跨平台 C/C++、教学 |
纯 Windows 桌面业务、用 C++ 做 GUI,选 MSVC 没毛病。但从 Linux/macOS 过来的项目、CMake 工程、以及需要 gcc 优化行为一致的场景,MinGW-w64 是补位选择。判断逻辑很简单:你的源码里有没有 Makefile、有没有 GCC 特有的编译选项、要不要在 Windows 上复现 Linux 下的编译结果——命中任何一条,直接考虑 MinGW-w64。
2.3 完整包与在线安装器的取舍:能离线就赢了
在线安装器最大的痛点是把编译器拆成几十个组件:gcc-core、gcc-g++、binutils、mingwrt、w32api……命名抽象,关系复杂,装完缺什么全靠编译时报错反向发现。网页版的引导下载器还看网络脸色,SourceForge 在国内的连通性时好时坏,下到一半断掉是常态。
完整包的价值就是把这一切变成离线 zip:一次解压得到一个完整的工具链目录,bin/include/lib/share 齐全。这也是课程资源里常见「lua5.1 基础环境包(luaforwindows_v5.1.5-52 及 mingw).zip」这类文件存在的原因——讲师把工具链和依赖打包在一个 zip 里,学生解压就能编译,省去环境折腾。同样逻辑的还有「带 mingw 的 codeblocks 安装包」,IDE 和编译器打包在一起,内部其实就是同一套工具链目录。
选完整包时我一般检查四个点,哪个缺了后面都是坑:
- 架构:x86_64 还是 i686,对应你的系统位数
- 线程模型:posix 还是 win32,决定 std::thread 能不能正常用
- 运行时:ucrt 还是 msvcrt,决定 C 标准库新旧
- 组件:bin 里是否同时存在 gcc.exe、g++.exe、gdb.exe、mingw32-make.exe
这四个点比版本号重要得多。版本号只影响新特性,这四个点直接决定能不能编译、能不能调试、能不能跑 Makefile。下一章安装步骤里,我按这四个点逐个过。
3. 完整包安装:从解压到 gcc --version 一次跑通
3.1 先确认两件事:系统位数和线程模型
打开 cmd,先确认系统位数:
echo %PROCESSOR_ARCHITECTURE%输出 AMD64 说明系统是 64 位,选 x86_64 开头的包;输出 x86 就只能用 32 位的 i686 包。这一步几乎不会错,真正容易错的是第二个选择——线程模型。
MinGW-w64 发行包的完整名称里通常会出现 posix 或 win32 字样,例如 x86_64-w64-mingw32-posix 和 x86_64-w64-mingw32-win32,这指的是线程模型。程序里用了 std::thread、std::async 这类 C++ 多线程设施时,libstdc++ 需要底层线程抽象:win32 模型直接走 Windows 原生 API,但 std::thread 的行为和 Linux 上有差异,部分源码在 win32 模型下编译会报错;posix 模型用 winpthreads 库模拟 pthread 接口,std::thread 用起来和 Linux 上基本一致。结论:除非你明确知道自己只写 C 语言、完全不碰线程,否则一律选 posix 版。运行时方面,如果下载页同时提供 msvcrt 和 ucrt 两个版本,选 ucrt;只有老项目需要兼容不带 UCRT 的 Win7 系统时,才回头考虑 msvcrt。
3.2 解压到固定目录:bin、include、lib 三件套必须齐全
完整包建议直接解压到 C:\mingw64,理由有两个:路径短、无空格。C:\Program Files\mingw64 这种带空格的路径,会让不少老 Makefile 和 CMake 配置脚本在转义环节翻车;路径短也方便后面 Eclipse、VSCode 配置时手敲,少打一串字符就少一次出错机会。
解压完不要急着配环境变量,先对着目录做一次体检。目标目录结构至少要有:
C:\mingw64\bin\gcc.exe C:\mingw64\bin\g++.exe C:\mingw64\bin\gdb.exe C:\mingw64\bin\mingw32-make.exe C:\mingw64\include\stdio.h C:\mingw64\lib\libstdc++.a哪个缺失基本能判断这个包不够格:没有 include 树的包,编译任何带头文件的代码都会报 fatal error;缺 gdb 只能编译不能调试;有的发行版不把 make 放 bin 里,或者文件名不叫 mingw32-make.exe,这种包最好直接换一个。体检这一步花不了两分钟,但能省下后面一晚上的排查时间,属于我自己的血泪经验。
3.3 环境变量设置:setx 的截断坑与 PowerShell 更稳的做法
PATH 分用户级和系统级:用户变量只对当前用户生效,系统变量全机器生效。普通开发机配用户级就够了,不用管理员权限。最常见的做法是 cmd 里用 setx:
setx PATH "%PATH%;C:\mingw64\bin"这条命令的逻辑是:把当前环境的 PATH 完整展开,追加 C:\mingw64\bin 再写回用户变量。坑就在「完整展开」四个字上:Windows 10/11 的系统 PATH 默认就有一长串条目,加上用户变量里的各种路径,很容易超过 setx 的限制——setx 对变量值只保留前 1024 字符。一旦截断,PATH 尾部一大半条目直接消失,后续启动其它工具就会开始报各种「不是内部或外部命令」。这个坑极其隐蔽,因为 gcc 可能恰好加上了,但某天你发现 git 或 npm 突然找不到了,回头一看 PATH 已经被截断得面目全非。
我一般不用 setx 处理 PATH,改用 PowerShell 里读取用户变量再追加,绕开展开合并的坑:
$old = [Environment]::GetEnvironmentVariable("Path", "User") [Environment]::SetEnvironmentVariable("Path", $old + ";C:\mingw64\bin", "User")逻辑说明:第一行只读取用户级的 Path,不碰进程 PATH,也不碰系统 PATH;第二行在用户级 Path 尾部追加一条,再写回。两个参数里的 "User" 指定了作用域,所以不会把系统 PATH 带进来,也不会有 1024 字符截断风险。配置完环境变量,接下来做一件经常被忽略的事:彻底关掉当前终端再重开。环境变量只对之后启动的进程生效,已经开着的终端不会自动刷新,很多新手配完直接在同一个窗口里敲 gcc,报错「不是内部或外部命令」,第一反应是配置没生效,其实是终端缓存作怪。
3.4 验收四连与第一个 hello.exe
重开终端后,敲四条命令,每一条都要能看到版本输出:
gcc --version g++ --version gdb --version mingw32-make --version逻辑说明:前两条确认 C 和 C++ 编译器就位,第三条确认调试器,第四条确认 Make 工具。接着单独跑一条 where gcc,确认命中的是 C:\mingw64\bin 下的 gcc:
where gcc如果 where 显示的是别的路径,说明 PATH 里还有一个旧编译器排在本包前面,比如 Git for Windows 自带的那套,这属于第 4 章要处理的经典冲突。
工具链没问题后,建一个工作目录,写最小程序验证整体链路:
#include <stdio.h> int main(void) { printf("mingw64 ok\n"); return 0; }编译时我习惯从第一次就带上警告和调试参数:
gcc -Wall -g hello.c -o hello.exe参数说明:-o 指定输出文件名 hello.exe;-Wall 打开所有常见警告,让代码问题在编译期暴露;-g 生成 gdb 调试信息,后面第 5 章进 Eclipse 调试时离不开它。运行:
./hello.exe能输出 mingw64 ok,说明编译器、链接器、运行时三环全通。到这里这份完整包的安装就算落地了,往后编译报错,理论上都可以把责任归给代码而不是环境。
4. 避坑:PATH 残留、缺 DLL 与 make 玄学的五处翻车记录
4.1 PATH 的两处经典翻车
翻车点一:新开的 cmd 敲 gcc 提示不是内部或外部命令。现象很直接,教程一步步执行完,重开终端仍然找不到 gcc。原因通常有两种:一是终端窗口没有真正刷新,很多终端软件开了「快速编辑」模式,新开窗口会复用旧进程的环境块;二是 PATH 根本没写进用户变量,比如 setx 因为截断或权限问题只写了一半。解决:先检查再动手改。在 cmd 里敲 set PATH,确认 C:\mingw64\bin 在不在;如果在,就关掉所有终端窗口,必要时注销一次重新登录;如果不在,回到第 3.3 节用 PowerShell 方法重新设置。注意 set PATH 查看的只是当前进程的 PATH,不是永久配置,两者要分清。
翻车点二:gcc --version 显示出一个完全陌生的版本号。现象是刚装的 MinGW-w64,敲 gcc 却输出了别的版本。原因:机器上本来就存在其它编译器,常见来源包括 Git for Windows 自带的 mingw、CodeBlocks 自带的 MinGW、TDM-GCC、MSYS2 的 usr\bin,还有某些 Python 包捆绑的编译器,它们在 PATH 里的顺序排在了 C:\mingw64\bin 前面。解决:用 where 把 gcc.exe 的命中路径全部列出来:
where gcc看输出顺序,把本包的路径挪到 PATH 最前面,或者把其它编译器从 PATH 里临时摘掉。这个问题同样适用于 g++、gdb、make,它们各自也有「李鬼」。
4.2 编译运行期的三处踩坑
问题一:编译简单文件直接报 fatal error: stdio.h: No such file or directory。现象是 gcc 能输出版本,一编译就炸,头文件全找不到。原因:手里的包没有完整的 include 目录,这是残缺包,常见于早期用 mingw-get 只装了 compiler 相关组件、漏装 runtime 的安装结果。解决:检查 C:\mingw64\include\stdio.h 是否存在,再检查 C:\mingw64\include\c++ 是否存在,后者一旦缺失,所有 C++ 源文件直接挂。如果确认包不全,别补了,换一个完整包。缺头的包修起来比换包还费时间,这是我踩过最不值得的坑。
问题二:本机编译运行一切正常,把 exe 拷到另一台电脑上双击报错「找不到 libgcc_s_seh-1.dll / libwinpthread-1.dll」。现象是目标电脑没装 MinGW,程序依赖的动态链接库不在系统目录里。原因:MinGW-w64 默认把 GCC 运行时动态链接进程序,libgcc_s_seh-1.dll 负责异常处理和辅助函数,libwinpthread-1.dll 只在 posix 线程模型包里出现。开发机上能运行是因为 C:\mingw64\bin 在 PATH 里,换一台干净的机器就露馅了。解决:把这两个 DLL 从 C:\mingw64\bin 拷到 exe 同目录,或者编译时加 -static-libgcc -static-libstdc++,最彻底的是用 -static 全静态链接,细节在第 6 章。
问题三:刚编译出的 exe 被 Windows Defender 直接隔离。现象是编译成功,杀软弹窗,文件从目录里消失,常见于带 winpthread 等 DLL 引用的新编译文件。原因:未经代码签名的本地编译产物容易命中 Defender 启发式规则的行为特征,gcc 新生成的 PE 文件确实有些特征像恶意程序打包器。解决:把开发工作目录加进 Defender 的排除路径,编译产物统一放这个目录下验证;真需要外发的文件再挪出来处理。注意这一步只需要加排除目录,不需要关闭整个实时防护,开发机安全底线还是要保留的。
5. Eclipse + MinGW-w64 实战:从源码到 Debug 的完整闭环
5.1 为什么用 Eclipse CDT 而不是硬把 GCC 塞进 VS
Visual Studio 的工程体系、调试器都是围绕 MSVC 设计的,GCC 编出来的程序带 DWARF 调试信息,VS 调试器不认;把 gcc 硬塞进 VS 不是不能用,而是每次构建、断点、看变量都在和各种机制对抗,体验很差。Eclipse CDT 不一样,它从设计上就是给 GNU 工具链用的:新建工程时直接扫描 PATH 里的 gcc/g++,自动拿到 include 路径列表,调试器默认接 gdb。这套组合在 Linux 上什么样,在 Windows 上还是什么样,对从 Linux 学习环境切换到 Windows 的人来说几乎零学习成本。
Eclipse CDT 从官方站点下载 Eclipse IDE for C/C++ Developers 这个版本就行,自带 CDT 插件,前提是本机有 JDK。单纯为了支撑 Eclipse 运行,装一个 openjdk 发行版即可,Eclipse 启动时会自动探测到 java.exe。Eclipse 本体解压即用,不需要安装步骤,这对刚被 MinGW 环境变量折腾过的人来说算是难得的省心环节。
5.2 新建 C 工程与 Toolchain 探测
打开 Eclipse,第一次启动会让你选 workspace 目录,建议单独建一个,不要放在 C:\mingw64 里,避免工具链目录被 IDE 配置文件污染。进入主界面后:File → New → C Project,项目类型最常用 Executable → Empty Project,空工程能自己控制源文件结构。往下拉到 Toolchains 列表,如果 CDT 正常工作,会出现 MinGW GCC 这一项,勾上它,Finish。
如果列表里没有 MinGW GCC,或者显示 No Toolchains,说明 Eclipse 进程的环境里看不到 gcc。最常见原因是 Eclipse 在配置 PATH 之前就启动了,桌面快捷方式继承的进程环境还是旧的。解决分两步:先完全退出 Eclipse 再重新启动,让新环境变量生效;如果重进仍然探测不到,手动到 Window → Preferences → C/C++ → Build → Environment 里新增一条变量,变量名写 PATH,值写 C:\mingw64\bin;%PATH%。这一步的本质是让 CDT 的启动扫描能找到 gcc.exe,和命令行里配 PATH 是同一个原理,只是面向的进程不同。
建完工程后,在 src 目录下新建源文件,把 hello.c 的代码放进去,Eclipse 的编辑器自带语法高亮和错误标注。这时如果源码里出现红色波浪线,先把鼠标悬停上去看提示,多数是 include 头文件找不到,在项目右键 Properties → C/C++ General → Paths and Symbols 里确认 GNU GCC 的自动发现是否勾选。
5.3 编译与 Debug:gdb 路径与断点单步
点工具栏锤子图标,Eclipse 在 Console 窗口输出完整构建命令和编译结果。能看到 gcc -O0 -g3 -Wall -c -fmessage-length=0 这类默认参数,这是 CDT 自带的构建配置。-O0 表示不优化,调试时变量可读性最好;-g3 生成完整调试信息,比手动命令行里的 -g 更细。如果 Console 里报 gcc 不是内部或外部命令,回到 5.2 的 PATH 设置,别怀疑完整包。
Debug 前先确认 gdb 路径。菜单 Run → Debug Configurations → C/C++ Application,左侧选中工程对应的配置,Main 标签页里确认 C/C++ Application 指向编译产物,Debugger 标签页把 gdb 路径浏览到 C:\mingw64\bin\gdb.exe。如果调试启动后报 Error while launching,十有八九是 gdb 路径指向了不存在的文件,或者 gdb 版本太旧读不懂当前编译器生成的调试符号。
调试的实际用法:在源码行号左侧双击设断点,按 F5 启动 Debug,程序停到断点后按 F6 单步执行,右侧 Variables 窗口实时看局部变量值。Windows 上用 gdb 调试时会弹出一个 Enter Debugger 窗口,那是 gdb 的终端交互窗口,正常现象,不要关,它承载着 gdb 的输入输出。整个流程跑通后,Eclipse 里的开发体验和 Linux 上几乎一致,断点、单步、变量观察都没有阉割。
6. 进阶:加一个 -static,让 exe 脱离 DLL 依赖
6.1 动态链接时你依赖了什么
新装的 MinGW-w64 编译一个 hello world,exe 在自己机器上跑得欢,拷到别人机器上就缺 DLL,第 4 章讲了这个现象,这一节给验证方法。用 binutils 自带的 objdump 查看 PE 文件的导入表:
objdump -p hello.exe | grep "DLL Name"逻辑说明:objdump -p 输出 PE 文件头里的可选头信息,grep "DLL Name" 把导入表里的 DLL 列表筛出来。动态链接版 hello.exe 的输出里,除了 KERNEL32.dll 这类系统 DLL,还会出现 libgcc_s_seh-1.dll;C++ 程序会多出 libstdc++-6.dll 和 libwinpthread-1.dll。这几个带 lib 前缀的 DLL,就是 MinGW-w64 运行时的体外依赖,分发给别人时漏掉它们,程序就启动不起来。
6.2 静态链接后的差异
把同样的源码换一条编译命令:
gcc -static hello.c -o hello_static.exe再跑一遍导入表检查:
objdump -p hello_static.exe | grep "DLL Name"正常情况只剩 KERNEL32.dll 和少数 Windows 系统 DLL,libgcc、libstdc++、libwinpthread 全部进了 exe 内部。文件体积会大几百 KB,换来的是 exe 单文件直接分发。如果不想全静态、只想去掉 GCC 运行时的依赖,可以用拆开的两个参数:
gcc -static-libgcc -static-libstdc++ hello.c -o hello.exe逻辑说明:-static 把 C 库和 C++ 库一并静态化,范围最大;-static-libgcc 和 -static-libstdc++ 只把 GCC 运行时静态化,C 库仍然动态。纯 C 代码用 -static 的行为差异很小;大工程全静态链接偶尔会遇到 winpthread 的已知问题,此时拆开参数更稳。
从那以后,我每次要交付一个 exe 出去,都会在最后强制跑一遍 objdump -p 检查导入表,看到 lib 开头的 DLL 就回去补编译参数,养成习惯后「拷到别的电脑缺 DLL」这类售后问题基本绝迹。希望帮到你。
本文还有配套的精品资源,点击获取