简介:面向64位Windows平台的MinGW-w64 GCC 7.1.0离线安装包,主要服务于需要在Windows下进行C/C++开发的学生、程序员及跨平台项目维护者,可缓解缺少原生编译工具链、环境配置繁琐等问题。压缩包为7z格式,共13449个文件,约44.58MB;内容以C/C++头文件和静态库为主体,含2086个.h、1358个.a、243个.hpp,并配有Python运行文件、72个exe、48个dll以及大量终端描述与文档配置,目录接近一套完整工具链。已有2474人学习下载。配置Path后即可调用gcc等命令,适合搭建本地编译环境、验证示例工程、排查头文件与链接依赖,也可用于旧项目复现和教学实验。
1. 版本对上不代表能用:那次 mingw 64位 gcc 7.1.0 安装包选错了线程模型
第一次在 Windows 上编一个图像处理小工具,同事丢过来一份 mingw 64位 gcc 7.1.0 安装包,说解压、加 PATH、完事。结果两个下午都耗在同一件事上:gcc -v显示 7.1.0 没错,可代码里一出现std::thread,链接阶段立刻一片红。后来才发现是包里的线程模型选了 win32,gcc 7.1.0 的 libstdc++ 在这个模型下压根没把线程支持编进去。这类工具链最坑的地方不是装不上,是装上了、版本号也对,编到一半才炸,报错还完全不指向真正的病因。Windows 上编 C/C++、跑跨平台小工具、维护那些锁死 GCC 7 的老构建脚本,这套环境几乎绕不开。下面按我实际落盘的顺序,把选包、解压、PATH、编译参数和排错一次写清。
2. 选对安装包:mingw-w64 gcc 7.1.0 的三种异常模型和目录结构
2.1 seh、sjlj、dwarf:三个词决定你后面会不会返工
mingw-w64 不是一个编译器,它是「Windows 上的 GCC 运行时 + 头文件 + 导入库」这一整套。同一份 7.1.0 的源码,打包的人会用不同的异常模型和线程模型编出好几个版本,文件名里那几个缩写就是标识。选错一个,后面就是重装。
| 模型 | 适用架构 | 机制 | 性能 | 兼容性 |
|---|---|---|---|---|
| seh | 仅 x86_64 | Windows 结构化异常 | 接近零开销 | 不覆盖 32 位目标 |
| sjlj | x86_64 / i686 | setjmp / longjmp | 每次 try 都有开销 | 最广,老代码友好 |
| dwarf | 仅 i686 | GCC 自己的栈展开 | 32 位里最优 | 只能用在 32 位 |
判断办法很简单,就是让它自己把宏打出来:
rem cmd 下用 nul 喂空输入,PowerShell 换成 echo "" | gcc -dM -E - gcc -dM -E - < nul | findstr /i "seh sjlj dwarf"有输出#define __SEH__ 1就是 seh 包,__SJLJ__就是 sjlj 包。这一步是装完后的第一件事,它比gcc --version更能说明你手里这个包到底是什么货。我一般把这个结果和gcc -v的输出一起截个图存进项目的docs/env.md,半年后回来查环境不用再猜。
2.2 解压后该看到什么:一份目录对照表
7.1.0 时代的 mingw-w64 基本是绿色包,解压出来是一个mingw64顶层目录,进到这一层才算对。有人把压缩包解开后多套了一层同名文件夹,结果 PATH 里写的是只包含另一个mingw64的路径,gcc.exe自然找不到。
| 路径 | 内容 | 判断标准 |
|---|---|---|
mingw64\bin | gcc.exe、g++.exe、gdb.exe、mingw32-make.exe、windres.exe | 这是唯一要进 PATH 的目录 |
mingw64\libexec\gcc\x86_64-w64-mingw32\7.1.0 | cc1.exe、cc1plus.exe、collect2.exe | 缺了它,编译会报 cannot execute 'cc1plus' |
mingw64\lib | libgcc_s_seh-1.dll、libstdc++-6.dll、libwinpthread-1.dll | 运行期 DLL 依赖的来源 |
mingw64\x86_64-w64-mingw32\include | Windows API 头文件 | 缺 windows.h 就是这里没解全 |
mingw64\x86_64-w64-mingw32\lib | 导入库 libkernel32.a 等 | 链接阶段找不到库先查这里 |
mingw64\share | locale、licenses | 少一两个不影响编译 |
bin目录里东西最杂,容易误判。真正要认的只有几个:gcc.exe、g++.exe、gdb.exe、mingw32-make.exe、windres.exe。看到gcc.exe就以为装好了,是新手最常见的误判,因为编译器真正的后端程序全在libexec下面。
2.3 posix 还是 win32:gcc 7.1.0 这条线只能选 posix
线程模型是第二个必须看的字段,因为它直接决定 C++11 的多线程能不能用。GCC 的 win32 线程模型在很长一段时间里没有实现std::thread、std::mutex、std::condition_variable,7.1.0 正好落在这段时间内。所以哪怕你去编一个最朴素的std::thread例子,链接器也会告诉你一堆 undefined reference。
// t.cpp:只用来看线程模型对不对,不涉及业务逻辑 #include <thread> #include <iostream> int main() { std::thread t([] { std::cout << "worker ok\n"; }); t.join(); return 0; }g++ -std=gnu++11 -pthread t.cpp -o t.exe-pthread在 posix 模型下会被展开成对 winpthreads 的链接,mingw32-make和 CMake 里的 Threads 查找也是靠它。posix 包的代价是多一个libwinpthread-1.dll的运行时依赖,发给别人的 exe 要么带上这个 DLL,要么在链接时加静态参数,第 4 章会写具体写法。至于「要不要为了少一个 DLL 去选 win32」,我的答案是不要:为了省一个 60KB 的 DLL,把整个 C++11 并发库放弃掉,不划算。
3. 落盘与 PATH:把 gcc 7.1.0 装进 C:\mingw64 的完整步骤
3.1 路径的三条硬规矩:英文、无空格、别放用户目录
工具链路径出错的比例远高于工具链本身出问题的比例。我踩过的两类:一是装在带中文的用户名目录下,C:\Users\张三\mingw64,某些老的构建脚本按 ANSI 读路径直接乱码;二是装在C:\Program Files下,普通权限的 cmd 里改不了内容,编译生成中间文件时报 access denied,看起来像编译器坏了。
我现在的固定做法是:真实目录带版本号,例如D:\toolchain\mingw64-7.1.0,再用一个目录联接把C:\mingw64指过去。这样以后上第二个版本,切链接就行,PATH 一个字都不用改。
rem 需要 cmd 以管理员身份运行;/J 是目录联接,不会复制文件 mklink /J C:\mingw64 D:\toolchain\mingw64-7.1.0/J建的是 junction,目标必须是本地 NTFS 路径,网络盘不行。切版本就是删掉链接重建一次,比来回改 PATH 干净得多。
3.2 解压与裸跑自检:先不配 PATH
7z 格式的包别用系统自带的解压,它对 7z 支持要么没有、要么慢,解到一半失败的情况我都遇到过。用 7-Zip 右键解压到D:\toolchain\,然后先别动环境变量,直接用绝对路径跑一次:
& "C:\mingw64\bin\gcc.exe" -v这一步的价值在于把故障面切成两半:绝对路径能跑通,说明包是完整的,后面报错就一定是 PATH 或环境的问题;绝对路径都跑不通,那就别折腾环境变量了,重新解压更省时间。
输出里认三个字段:
Target: x86_64-w64-mingw32—— 证明这是 64 位包Thread model: posix—— 证明线程模型对了gcc version 7.1.0—— 版本号
三个有一个不对,直接换包。这时候还没配 PATH,返工成本最低。
3.3 PATH 的两种加法,以及会膨胀的 setx
会话级是最安全的,只在当前窗口有效,关掉就恢复:
set "PATH=C:\mingw64\bin;%PATH%" where gccwhere gcc的输出必须只有一行,且指向C:\mingw64\bin\gcc.exe。如果输出两行以上,说明系统里还有别的 gcc(Anaconda 自带的那份最常见),后面会讲到怎么处理。
想永久生效,别用setx PATH "%PATH%;C:\mingw64\bin"。这条命令看着人畜无害,实际上是把「机器级 PATH + 用户级 PATH」合并展开后,整个写回用户变量,用户变量里从此多了一份机器级的副本;反复执行几次,PATH 会膨胀到超过 setx 的 1024 字符上限,被静默截断,然后你的其他工具就集体失踪了。这是我最贵的一次血泪经验。
正确的写法是只读用户级、只追加用户级:
# 只取用户级 Path,避免把机器级内容复制进来 $old = [Environment]::GetEnvironmentVariable('Path', 'User') if ($old -notlike '*C:\mingw64\bin*') { [Environment]::SetEnvironmentVariable('Path', "C:\mingw64\bin;$old", 'User') }改完必须新开一个 cmd 或 PowerShell 窗口,已经开着的窗口不会重新读环境变量,这一点每天都有人在这里怀疑人生。
3.4 多版本共存:一个只在当前窗口生效的切换脚本
机器上同时有 GCC 7.1.0 和更高版本是常态,尤其是要复现老项目的构建结果。别用全局 setx 来回横跳,写个小脚本放在D:\toolchain\:
@echo off rem gcc7.bat:只影响当前窗口,退出即恢复 set "MINGW_HOME=C:\mingw64" set "PATH=%MINGW_HOME%\bin;%PATH%" where gcc gcc --version | findstr /r "7\.1\.0" >nul && echo [OK] gcc 7.1.0 in use || echo [FAIL] version mismatch cmd /kcmd /k是为了让新窗口继承这个 PATH 并保持打开,脚本本身不污染系统。日常开发我把这一层封在项目根目录的env.bat里,谁拉代码谁跑一遍,环境差异能少一大半。
4. 编译链配置:让 gcc 7.1.0 真的能编 C++11 和静态链接
4.1 四件套自检:gcc、g++、gdb、mingw32-make
PATH 配好后先把四个可执行文件点一遍,缺哪个补哪个,别等到编译到一半才发现没有 make。
where gcc g++ gdb mingw32-make gcc --version g++ --version mingw32-make --version gdb --versionwhere一次给四个名字,输出顺序和参数顺序一致,任何一行是「找不到文件」就说明包不全或者 PATH 只加对了一半。注意make在这个包里叫mingw32-make.exe,不叫make.exe,很多从 Linux 迁过来的 Makefile 第一行就栽在这。
4.2 编译参数:默认标准、-m64 和两种静态链接
gcc 7.1.0 的默认标准是 C 的gnu11和 C++ 的gnu++14,不是很多人以为的 C++11。项目要求 C++11 时我一般显式写上,避免默认值随版本漂移。
g++ -std=gnu++11 -m64 -O2 -Wall -Wextra ^ -static-libgcc -static-libstdc++ ^ -o app.exe main.cpp-std=gnu++11保留 GNU 扩展,老代码里typeof、__attribute__这类写法不会突然报错;要严格标准就换成-std=c++11。-m64在 x86_64 包上本来就是默认,写上是防止某天误加-m32之后才发现这个包根本编不了 32 位,报错信息会误导你去查库。-static-libgcc -static-libstdc++只静态链接编译器运行库,系统 DLL 仍然动态,产物体积增加有限,但换来的是别人机器上不会缺libstdc++-6.dll。- 想彻底静态,用
-static,但它会把 winpthread 也静态进来,某些涉及线程创建的场景需要确认一下版本行为,别盲加。
4.3 CMake 与 Makefile:把编译器路径写死
CMake 在 Windows 上默认找 MSVC,第一次配置如果不指定,生成器会静默选 Visual Studio,然后你在 CMakeCache 里看到一堆cl.exe,人直接傻掉。最稳的写法是首次配置就把编译器和生成器一起钉死:
cmake -G "MinGW Makefiles" ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_C_COMPILER="C:/mingw64/bin/gcc.exe" ^ -DCMAKE_CXX_COMPILER="C:/mingw64/bin/g++.exe" .. mingw32-make -j4CMake 里路径一律用正斜杠或者双反斜杠,单反斜杠是转义符,C:\mingw64会被吃成C:mingw64。另一个办法是配置前设环境变量,让 CMake 自己去读:
set "CC=C:\mingw64\bin\gcc.exe" set "CXX=C:\mingw64\bin\g++.exe"注意CC/CXX只在首次配置(生成 CMakeCache.txt)时有效,缓存已经生成之后再改环境变量没用,得删掉build目录重来。这一条我吃过不止一次亏。
手写 Makefile 的话,把工具链前缀单独提出来,换版本只改一行:
# 路径用正斜杠,避免 make 把反斜杠当续行 CXX := C:/mingw64/bin/g++.exe CXXFLAGS := -std=gnu++11 -O2 -Wall -Wextra LDFLAGS := -static-libgcc -static-libstdc++ TARGET := app.exe OBJS := main.o util.o $(TARGET): $(OBJS) $(CXX) $(OBJS) $(LDFLAGS) -o $@4.4 gdb 的几行初始化配置
调试器不配也能用,但每跑一次都要按好几下翻页,效率极低。在用户目录下建一个.gdbinit:
set pagination off set confirm off set print pretty onpagination off关掉分页提示,print pretty on让 STL 容器打印出可读结构。gdb 7.x 读的是%USERPROFILE%\.gdbinit,如果放进去不生效,用gdb -x 路径显式指定一次,确认是不是 home 路径识别的问题。
5. 装完出问题怎么排查:gcc 7.1.0 最常见的五个失败场景
5.1 提示「不是内部或外部命令」,但 bin 目录里明明有 gcc.exe
现象:where gcc报找不到,或者输出指向了另一个目录,gcc --version出来的版本不是 7.1.0。
原因:PATH 没生效、加错了层级(加成了C:\mingw64而不是C:\mingw64\bin),或者系统里已有优先级更高的同名 exe,典型是某科学计算发行版自带的 gcc 排在前面。
解决:先在新窗口执行where gcc,看实际命中的路径;确认 PATH 里是bin这一层;把 mingw 的bin放到 PATH 最前面,别放在末尾和别的工具抢位置。
5.2 编译报 cannot execute 'cc1plus'
现象:g++能启动,但一编译就提示找不到cc1plus,路径里还带着一长串libexec。
原因:包解压不完整,libexec\gcc\x86_64-w64-mingw32\7.1.0\下缺文件;或者你只把gcc.exe拷到别处,脱离了它依赖的相对目录结构。
解决:整个mingw64目录必须完整保留,不能单独搬 exe。确认真实路径下cc1.exe、cc1plus.exe、collect2.exe都在;缺了就重新解压,不要尝试从别处拷一个补上,版本不匹配会引出更怪的报错。
5.3 编译通过,双击 exe 提示缺 libgcc_s_seh-1.dll 或 libstdc++-6.dll
现象:在开发机运行正常,发给别人或者在别的目录下运行就弹窗缺 DLL。
原因:C++ 程序的运行库默认动态链接,libstdc++-6.dll、libgcc_s_seh-1.dll、libwinpthread-1.dll都是外部依赖,只有 PATH 里有 mingw 的 bin 时才找得到。
解决:链接时加-static-libgcc -static-libstdc++;用了线程的再加-Wl,-Bstatic -lwinpthread -Wl,-Bdynamic,或者直接-static。临时应急可以把三个 DLL 拷到 exe 同目录,但这只是权宜之计,不能作为发布方案。
5.4 CMake 配置报 "MinGW Makefiles" 生成器失败,或者干脆用了 MSVC
现象:cmake -G "MinGW Makefiles"报错退出,或者配置成功了但编译时调的是cl.exe。
原因:两类。一类是 PATH 里存在sh.exe(某些命令行环境会带),老版本 CMake 的 MinGW 生成器会因为这个直接拒绝;另一类是没指定编译器,CMake 按平台默认选了 MSVC。
解决:配置时显式传-DCMAKE_C_COMPILER和-DCMAKE_CXX_COMPILER,一次到位;确认where sh没有输出,有的话临时从 PATH 里摘掉;已经生成错误缓存的,删掉整个 build 目录重新配置,改缓存文件是自找麻烦。
5.5 编译突然变慢,或者 gdb 启动卡在 Starting program
现象:同样的代码,之前几秒编完,现在要几十秒;或者 gdb 一按 run 就卡住不动。
原因:杀毒软件对libexec下频繁调用的cc1plus.exe做实时扫描;gdb 卡住多半是调试信息格式与杀软监控冲突,或者程序在等标准输入。
解决:把工具链目录和项目 build 目录加进杀软的排除列表,这是最有效的一招;gdb 卡住先确认程序本身没有cin >>之类的阻塞,再考虑换-g3为-g缩小调试信息体积。这类问题没有银弹,只能靠排除法缩小范围。
6. 装完怎么验证:一套五分钟能跑完的自检流程
判断这套环境到底装没装成,不能只看gcc --version。我做验收时会跑一遍从源码到可执行文件、再到调试器的最小闭环,五分钟之内能得出确定结论。
第一步,验证编译器身份和模型:
gcc -v 2>&1 | findstr /i "target threadmodel gcc version" gcc -dM -E - < nul | findstr /i "seh sjlj"要看到x86_64-w64-mingw32、posix、7.1.0,以及__SEH__。四个都齐,说明包选对了。
第二步,编一个真正用上 C++11 特性和线程的程序,别用 hello world 糊弄自己:
g++ -std=gnu++11 -pthread -static-libgcc -static-libstdc++ t.cpp -o t.exe t.exe能打印出结果,才证明 libstdc++ 的线程部分真的可用。这一步是我判断「装完」和「装对」的分界线。
第三步,做依赖体检,确认发布时不会缺 DLL:
objdump -p t.exe | findstr /i "DLL Name"下面这张表是我实际项目里对着看的判据:
| 检查项 | 期望结果 | 不达标说明 |
|---|---|---|
DLL Name列表 | 只剩系统 DLL(kernel32、msvcrt 等) | 出现 libstdc++-6.dll 说明静态链接没生效 |
where gcc | 唯一命中C:\mingw64\bin\gcc.exe | 多行说明有其他工具链抢占 |
gcc -dM -E | 有__SEH__、__x86_64__ | 缺一个就是包不对 |
gdb --version | 能正常输出 | 报错说明 bin 不完整 |
mingw32-make -j4 | 正常并发构建 | 找不到命令说明包名没对上 |
第四步,用 gdb 挂一次,break main能停下、print能出值,就算调试链也通了。整套走完不超过五分钟,比出问题后花两小时回溯划算得多。
从那以后我每装一次工具链,都强制走一遍这套自检,并且把gcc -v和三步验证的输出贴进项目文档,谁的环境出问题先对照这份快照,能省掉大量「你那儿能跑我这儿不能跑」的扯皮。这套 mingw-w64 gcc 7.1.0 的完整安装包可以直接取用,解压后先按第 2 章的目录表对一遍,再动 PATH,能避开大半返工。希望帮到你。
本文还有配套的精品资源,点击获取