简介:这是一份面向 Windows 64 位平台的 MinGW-w64 开发工具集,专为需要在本地编译 C/C++ 程序、生成 DLL 动态库或编写 JNI 接口的开发者准备。压缩包内置完整的 mingw64 目录,解压即可使用 gcc/g++,并采用 POSIX 信号处理与 SEH 结构化异常处理组合,兼顾 Linux 编程习惯与 Windows 异常机制,可避免从官网下载慢、失败或缺失 64 位组件的困扰。
整个压缩包 141.38MB,共 2000 个文件,类型以 C/C++ 头文件(h/hpp)、静态库(a/lib)、动态库(dll)、可执行工具(exe)及 Python 脚本与扩展文件(py/pyc/pyd)为主,覆盖编译器、链接器、标准库头文件与辅助工具链,并包含大量终端与编码相关资源,便于在不同开发环境下使用。
目前已有 2466 人学习。通过该压缩包可快速获得完整 MinGW-w64 离线环境,省去手动配置多个组件的步骤,适合在 Windows 下进行 C/C++ 开发、JNI 本地方法调用、DLL 编译验证的中高级开发者作为离线工具包收藏使用。
1. 下错包、配不对路径:mingw_x86_64-posix-seh到底是个什么
很多第一次在 Windows 上折腾 C 编译器的开发者,都在某个下载页看到过mingw_x86_64-posix-seh这个压缩包名,解压之后面对一堆目录发愣,问“这算不算装好了”。这个包本质上是 MinGW-w64 项目预编译好的 GCC 工具链,它把编译器、汇编器、链接器、调试器和 Windows 头文件库打包在一起,省去了自己从源码编一套 C 编译器的巨大成本。只要你能正确配置环境变量并避开几个常见的坑,它就能在 Windows 上编译出原生 .exe 程序,替代 Visual Studio 的 MSVC 工具链。这篇笔记就围绕这个包名拆解:三个关键字决定什么、目录里实际装了什么、怎么配才不翻车,以及我在反复重装中踩过的具体问题。
2. 拆包之前先看懂关键字:x86_64、posix、seh 分别决定了什么
2.1 包名的三个关键字,错过一个都是重装
mingw_x86_64-posix-seh不是随机字符串,它依次描述了目标架构、线程模型和异常处理模型,这三个参数直接决定你能编译出什么样的程序,以及哪些代码能在这个工具链上正常跑。
x86_64 指目标 CPU 架构是 64 位。编译器默认生成 PE32+ 格式的 64 位 .exe,在 64 位 Windows 上运行。这里第一个常见误判是:很多人以为这个包可以顺便编 32 位程序,加个-m32就行。实际上这个发行包默认不含 32 位 multilib 库,执行gcc -m32 hello.c通常会报fatal error: stdio.h: No such file or directory。需要 32 位输出时,我一般直接下载 i686 版本的工具链,而不是在同一套环境里硬切。
posix 是线程模型。MinGW-w64 的线程实现分 win32 和 posix 两种:win32 模型底层直接调用 Windows API,posix 模型则实现了 POSIX threads 接口。C++11 之后<thread>和<mutex>在两种模型下都能用,但如果你写了pthread_create这类 POSIX 接口的代码,就必须选 posix 模型,否则链接阶段直接报未定义引用。跨平台代码优先选 posix,这也是很多开源项目在 Windows 上推荐 posix 版本的原因。
seh 指异常处理采用 Windows 的结构化异常处理机制。64 位平台上 MinGW-w64 基本默认用 seh,对比老旧的 dwarf(调试帧驱动)和 sjlj(setjmp/longjmp 回退)方式,seh 在 64 位环境下的性能和调试体验最好,异常抛出的调用栈信息更准确。简而言之,这个包名的完整含义是:面向 x86_64 架构、使用 POSIX 线程接口、基于 SEH 异常模型的 MinGW-w64 GCC 工具链。
2.2 解压之后,bin 目录里到底装了什么
解压后第一件事不是急着找 gcc.exe,而是看清 bin 目录里的文件构成。实用工具列表如下,这也是判断一个 MinGW 发行包是否完整的基本标准,缺少任何一项,后续编译大概率会在某个环节卡住。
| 文件名 | 作用 | 什么时候必须用到 |
|---|---|---|
| gcc.exe | C 语言编译器驱动 | 编译 .c 文件 |
| g++.exe | C++ 编译器驱动 | 编译 .cpp 文件 |
| x86_64-w64-mingw32-gcc.exe | 带目标前缀的编译器 | 交叉编译或 Makefile 显式指定 |
| mingw32-make.exe | GNU make 的 Windows 移植 | 执行 Makefile 构建 |
| ld.exe | GNU 链接器 | 链接目标文件生成可执行文件 |
| gdb.exe | GNU 调试器 | 命令行调试程序 |
| objdump.exe | 查看 PE 文件结构、依赖 DLL | 检查生成的可执行文件 |
| objcopy.exe / strip.exe | 目标文件格式转换、符号裁剪 | 减小程序体积 |
| windres.exe | Windows 资源文件编译器 | 编译 .rc 资源(图标、版本信息) |
要注意 bin 下还有一串x86_64-w64-mingw32-*前缀的工具。这个前缀叫 target triplet,表示这套工具链的目标平台。Makefile 里如果写成CC=x86_64-w64-mingw32-gcc,就是为了避免系统里同时装了 Cygwin 或别的 GCC 时串台。日常手动编译我直接用 gcc.exe 就够了,但在自动化构建脚本里显式指定带前缀的版本更稳。
2.3 为什么选 MinGW-w64 而不是 Cygwin 或 MSVC
把 MinGW-w64 和另两个方案放一起对比,能更清楚它的适用边界。Cygwin 的编译产物依赖 Cygwin1.dll,这个 DLL 模拟了 POSIX 环境,能让 Unix 程序在 Windows 上跑,但性能和部署都被那一层模拟拖累;MinGW-w64 直接链接 Windows 系统 DLL,生成的程序是“原生”的 Windows 可执行文件,不需要额外运行时。MSVC 是 Windows 生态的官方选择,调试器集成度极高,但它的 CRT 实现和 GCC 的 libstdc++ 在 ABI 上不兼容,很多开源代码在 MSVC 下编译会报语法错误或库函数缺失,而 GCC 对 C 标准和 POSIX 接口的支持更贴近 Linux 环境。
| 对比维度 | MinGW-w64 | Cygwin | MSVC |
|---|---|---|---|
| 产物是否原生 | 原生 PE 可执行文件 | 依赖 Cygwin1.dll | 原生 PE 可执行文件 |
| POSIX 接口支持 | 有限支持,常用 pthread 可用 | 完整模拟 | 基本不支持 |
| C/C++ 标准支持 | GCC 驱动,标准支持广 | GCC 驱动,同左 | 对较新的 C 标准跟进慢 |
| 开源代码兼容性 | 高,很多项目直接编译通过 | 最高,但需带运行时 | 低,常需改代码 |
所以这个mingw_x86_64-posix-seh发行包最适合的场景是:在 Windows 上编译需要 pthread 的跨平台 C/C++ 项目,或者想把 Linux 下写的代码快速迁移到 Windows 跑。纯 Windows 原生开发如果不在乎开源兼容性,MSVC 依然是更省心的选择;而如果你的程序最终要跑在 Linux 服务器上,那这套工具链也只是“编译目标是 Windows 的交叉环境”,最终的部署环境还是要另算。
3. 安装配置与 IDE 整合:把工具链变成可用的 C 编译器
3.1 环境变量配置的两种方式,以及为什么重启后失效
MinGW 工具链解压后不会自动注册到系统,所谓“安装”其实就是让 shell 能找到 bin 目录下的 gcc.exe。最常见的两种做法如下,手动配置适合临时验证,系统级配置适合长期开发。
我一般先验证解压路径是否正确,再做配置。假设解压到了D:\dev\mingw64,在 Git Bash 或 MSYS2 终端里做临时配置的方式如下。
# 临时添加环境变量,仅对当前终端有效 export PATH="/d/dev/mingw64/bin:$PATH" # 验证编译器版本和搜索路径 gcc --version which gcc这段配置的逻辑是把 MinGW 的 bin 目录追加到 PATH 最前面。/d/dev/mingw64是 MSYS2 风格的路径写法,对应 Windows 的D:\dev\mingw64。把 bin 放在 PATH 前面,是为了避免系统里存在其他 gcc 时被优先调用。which gcc能确认当前解析到的 gcc 是不是 MinGW 的,这一步很重要——我见过有人配完gcc --version显示的是 WSL 里那个 gcc,编译出来的 ELF 文件在 Windows 下根本跑不了。
但注意:这个 export 只对当前终端生效,关掉窗口就没了。要让 Visual Studio Code、CLion 这些 IDE 的终端也能直接用,需要写入 Windows 系统环境变量。命令行方式如下。
# 以管理员身份运行 PowerShell,写入系统级 PATH [Environment]::SetEnvironmentVariable("Path", $env:Path + ";D:\dev\mingw64\bin", "Machine")这条命令把 MinGW 的 bin 目录追加到系统 PATH。“Machine”作用域表示对所有用户生效,普通用户权限不够会报安全错误。设置完系统 PATH 后,必须重新打开终端才能读到新值,因为已运行的进程不会自动刷新环境变量。这就是很多新手配完环境变量却仍然报“gcc 不是内部或外部命令”的原因——不是没配上,是没重开终端。
3.2 编译第一个 C 程序,并验证产物是原生 PE 可执行文件
配置完成后,用最小程序验证整个工具链是否闭环工作。我习惯把测试代码写得极简,排除业务逻辑干扰,只验证编译器本身。
// hello_mingw.c #include <stdio.h> int main(void) { printf("mingw gcc ok\n"); return 0; }编译命令如下:
# 单步编译:预处理、编译、汇编、链接一步完成 gcc hello_mingw.c -o hello_mingw.exe # 查看可执行文件类型 file hello_mingw.exe # 运行验证 ./hello_mingw.exegcc hello_mingw.c -o hello_mingw.exe是完整的编译链接过程,-o指定输出文件名。如果不加-o,默认会生成 a.exe。file命令在 Git Bash 或 MSYS2 里可用,输出里能看到PE32+ executable (console) x86-64这样的描述,PE32+ 表示这是 64 位 Windows 原生产物,与 Linux 的 ELF 格式区分明确,这一步能确认没有误用其他平台的编译器。运行输出mingw gcc ok即表示工具链闭环正常。
如果只是验证语法正确性而不想生成可执行文件,可以加-fsyntax-only参数,适合在写头文件时做快速检查,速度比完整编译快很多。
3.3 接入 VSCode 和 CLion:tasks.json 与 toolchain 配置
命令行能用之后,下一步是让 IDE 认识这套编译器。VSCode 的配置集中在.vscode/tasks.json和.vscode/launch.json里,tasks.json 负责编译动作,launch.json 负责调试动作。以下是一组能直接用的最小配置。
// .vscode/tasks.json { "version": "2.0.0", "tasks": [ { "label": "build with mingw gcc", "type": "shell", "command": "gcc", "args": [ "-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}.exe" ], "group": { "kind": "build", "isDefault": true }, "problemMatcher": ["$gcc"] } ] }"type": "shell"表示通过 shell 执行命令,command指定 gcc,注意这里不再写完整路径,依赖前面配好的系统 PATH。-g生成调试信息,是 gdb 能够断点调试的前提。${file}、${fileDirname}、${fileBasenameNoExtension}是 VSCode 的变量,分别代表当前打开的文件、文件所在目录、不带扩展名的文件名。problemMatcher里的$gcc让 VSCode 能识别 gcc 的输出格式并显示在“问题”面板。
调试配置如下。
// .vscode/launch.json { "version": "0.2.0", "configurations": [ { "name": "gdb debug", "type": "cppdbg", "request": "launch", "program": "${fileDirname}/${fileBasenameNoExtension}.exe", "args": [], "stopAtEntry": false, "cwd": "${fileDirname}", "environment": [], "externalConsole": false, "MIMode": "gdb", "miDebuggerPath": "D:/dev/mingw64/bin/gdb.exe", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] } ] }program指定被调试的可执行文件路径,miDebuggerPath必须显式指到 gdb.exe 的完整路径,因为 VSCode 的 cppdbg 调试器不会自动查找 PATH。stopAtEntry: false表示不自动停在程序入口,断点由你在源码里手动设置。externalConsole: false让输出显示在 VSCode 集成终端里,避免弹出系统黑窗口。
CLion 的接入方式是在 Settings 的 Build Tools 里新增 Toolchain,Compiler 选到D:/dev/mingw64/bin/gcc.exe,C++ Compiler 选同目录的 g++.exe,Debugger 选 gdb.exe,Make 程序选 mingw32-make.exe。CLion 会自动探测,但 Windows 下偶尔识别不全,手动指向缺一不可。
4. 避坑:在 Windows 上被 MinGW 坑过的五个具体场景
4.1 编译报“gcc 不是内部或外部命令”,但环境变量明明配了
现象:终端执行gcc --version报错,提示命令不存在,但系统环境变量里分明已经加入了 MinGW 的 bin 目录路径。
原因:配置完系统环境变量后,终端进程的环境变量是启动瞬间读取的快照,旧进程不会自动同步新配置。还有一种情况是 PATH 里新旧路径拼接出错,比如分号写成了中文全角分号,导致整条 PATH 解析失败。
解决:彻底关闭所有终端窗口和 IDE,重新打开。如果还不行,执行echo %PATH%或echo $PATH检查 bin 目录是否在输出里。确认路径存在但命令仍找不到时,检查 PATH 里的分隔符必须全部是英文分号。我最终习惯在系统环境变量里给 MinGW 单独建一个变量名,再在 PATH 里引用它,这样排错时能快速定位是哪一段拼接出的问题。
4.2 运行编译出的 exe 提示缺少 libstdc++-6.dll
现象:编译阶段一切正常,双击 exe 或命令行运行时弹出“无法启动此程序,因为计算机中丢失 libstdc++-6.dll”的对话框。
原因:g++.exe 默认动态链接 GCC 的 C++ 标准库,运行时可执行文件会去系统 DLL 搜索路径找 libstdc++-6.dll,而 MinGW 的 bin 目录不在默认搜索路径里。编译 C 程序时通常不缺这个 DLL,所以很多人第一次写 C++ 程序才遇到。
解决:两个思路。其一,把 MinGW 的 bin 目录加入系统 PATH,让运行时能找到 DLL,适合开发阶段;其二,编译时加静态链接参数,把标准库直接编进 exe,g++ -static-libgcc -static-libstdc++ hello.cpp -o hello.exe,适合分发程序时使用。我分发工具类的程序一律用静态链接,避免目标机器上缺运行库,代价是 exe 体积增大几兆,这个交易在多数场景下划算。
4.3 源码含中文时,编译运行出现乱码
现象:程序里写了printf("你好"),在 Windows 控制台运行输出一堆乱码,换到 Win10 之后乱码形式还可能不太一样。
原因:工具链默认把源代码按 UTF-8 解析,但 Windows 控制台的代码页通常是 GBK(936)或 UTF-8 取决于系统区域设置。源码里字符串常量的编码和执行环境代码页不一致时,打印出的字节被控制台按另一种编码解读,就显示成乱码。
解决:编译时指定执行编码让字符串字面量转成目标代码页。在控制台仍为 GBK 的系统上,加上-fexec-charset=GBK,例如gcc hello.c -o hello.exe -fexec-charset=GBK。如果系统已经是 UTF-8 代码页,就不需要这个参数。还有另一种思路是源码文件本身保存为 GBK 编码,编译时加-finput-charset=GBK,但跨平台协作时源码统一 UTF-8 更省事,所以我的做法是代码文件一律 UTF-8,编译参数按目标运行环境走。
4.4 杀毒软件把编译出的 exe 或编译器本身隔离
现象:编译生成可执行文件的瞬间,安全软件弹窗提示“木马”,直接把文件删了;更尴尬的是 gcc.exe 本身也被隔离,重新解压后又再次被处理。
原因:某些安全引擎对未签名的 PE 文件特征敏感,尤其是包含 GCC 运行时特征的可执行文件容易被误判。MinGW 的 exe 大概率没有数字签名,加上 seh 异常处理的代码段特征在某些引擎的黑名单里,就会触发查杀。
解决:把整个 MinGW 目录加入安全软件的白名单,再把编译输出的目录也加进去。如果项目要正式对外分发,建议用官方渠道重新下载工具链后用公钥或哈希校验文件完整性,确认不是真的被植入过木马。我自己遇到过同样的 gcc.exe 在两个不同设备的杀软下结果不同,这类问题处理完继续开发即可,不用过度紧张,但校验哈希这一步不要省。
4.5 使用 Makefile 构建失败,短横杠命令和 shell 语法不可用
现象:把 Linux 上的 Makefile 直接拿到 Windows 上用 make 执行,报错process_begin: CreateProcess(NULL, rm -f, ...) failed,或者一堆 shell 通配符和管道语法不识别。
原因:Windows 版的 make(mingw32-make.exe)在调用规则里的 shell 命令时,默认用的是 cmd.exe,而不是 Linux 里的 /bin/sh,所以rm -f、ls *.c这些命令在 cmd 里根本没有,导致规则执行失败。
解决:改用 mingw32-make.exe 执行并修改 Makefile 里的平台相关命令。rm 换成del /q,或者干脆在 Makefile 里加一个clean规则用-$(RM)这类变量。更高层的做法是在 Makefile 顶部加条件判断区分平台:
ifeq ($(OS), Windows_NT) RM = del /q EXE = .exe else RM = rm -f EXE = endif这样同一套 Makefile 在 Windows 和 Linux 下都能跑,代价是维护逻辑多一点。我的经验是:凡是要跨平台的 C/C++ 项目,Makefile 里的 shell 命令越少越好,能交给编译器的参数就不要用脚本去处理文件,能大幅减少这类冲突。
5. 让编译产物脱离开发机:静态链接与 PE 文件体检
5.1 用一套参数把运行库打进 exe
开发阶段动态链接无可厚非,但编译产物要在别的 Windows 机器上跑,就得把运行库绑进去。我常用的命令是-static配合两个标准库参数,一步到位。
g++ main.cpp -o app.exe -O2 -static -static-libgcc -static-libstdc++-static让链接器尽量静态链接所有库,-static-libgcc和-static-libstdc++分别强制静态链接 GCC 底层库和 C++ 标准库,合在一起保证不依赖 libstdc++-6.dll 和 libgcc_s_seh-1.dll。-O2是优化等级,生成速度与代码体积相对均衡。加了这组参数后,编译出的 exe 在干净的 Windows 环境里可以直接双击运行,不再依赖 PATH。
5.2 用 objdump 查看 DLL 依赖和代码段分布
验证一个 exe 是否做到了“脱离环境”,最直接的手段是查看它的导入表,看它到底依赖哪些 DLL。
# 查看 exe 依赖的外部 DLL 列表 objdump -p app.exe | grep "DLL Name" # 查看各 section 占比,直观了解体积构成 objdump -h app.exeobjdump -p显示 PE 头信息,grep 过滤出DLL Name行,能看到 kernel32.dll、user32.dll 这些 Windows 系统 DLL 是正常的,如果出现 libstdc++-6.dll 就说明还有动态依赖在。objdump -h列出所有 section 及大小,.text是代码段,.data是已初始化数据,.bss是未初始化数据,.rdata是只读数据。检查这两个输出,基本能判断编出来的程序是否干净、体积消耗在哪里。
5.3 分步观察编译各阶段,定位深层语法错误
项目规模一大,编译错误信息被优化过程包裹时很难直接定位到源码行。遇到这种情况,我习惯把编译拆解成预处理、语法转换、汇编、链接四步观察。
# 预处理:展开头文件和宏 gcc -E main.c -o main.i # 语法编译:生成汇编代码 gcc -S main.i -o main.s # 汇编:生成目标文件 gcc -c main.s -o main.o # 链接:生成最终可执行文件 gcc main.o -o main.exe-E展开所有预处理指令,宏定义、头文件内容都会体现在 main.i 里,如果某个头文件没找到,在这步就能看出来。-S输出汇编代码,复杂表达式展开后的结果在这里最直观,内联函数的展开、栈帧的处理都能看到。-c只生成目标文件不做链接,用于隔离“代码语法错误”和“链接缺失符号”两类问题。最后一步链接如果报未定义引用,问题出在库文件或函数符号上;如果前几步就报错,那基本上就是源码本身的问题。这套步骤做一次最多一分钟,却能把复杂报错缩小到一个阶段。
我从那以后每次拿到新的 MinGW 工具链,都会强制走一遍验证流程:解压后先看 bin 目录完整性,再配 PATH,接着编译一个带中文输出的 C 程序和一个调用 pthread 的 C++ 程序,最后确认 exe 能在未安装工具链的机器上运行。这套流程跑完,工具链的环境问题基本杜绝了。希望这篇笔记能帮你少走我当年绕过的弯路。
本文还有配套的精品资源,点击获取