Windows下MinGW-w64安装配置详解:从零搭建GCC编译环境
2026/9/13 16:44:52 网站建设 项目流程

1. 为什么Windows开发者需要一个正经的GCC编译器

先说个扎心的事实:大部分人在Windows上第一次接触C/C++编程,用的都是Visual Studio。VS确实够强,整套IDE、调试器、编译器打包得严严实实,但只要你离开VS生态半步,问题就来了——CMake项目拉不下来、Linux上写好的代码在Windows上编不过、想用GCC专属的内置函数和扩展语法直接抓瞎、CI里跑个交叉编译脚本更是绕不开命令行。这时候MinGW-w64就是你必须补上的那块拼图。

MinGW-w64是GCC编译器套件在Windows平台上的移植版,全称是Minimalist GNU for Windows(64位及32位)。它原生编译出Windows可执行文件,不依赖任何第三方运行时库,生成的是真正的PE格式exe,跑在用户电脑上不需要额外装环境。很多开源项目、嵌入式工具链(比如ARM交叉编译器)、CI流水线(GitHub Actions的windows-latest镜像)默认用的就是MinGW-w64。

这篇文章写给我自己,也写给所有在Windows上折腾C/C++工具链的朋友。我会从零开始,把MinGW-w64的下载、安装、环境变量配置、编译验证、常见坑全部过一遍,每一步都写清楚为什么这么做,而不是直接甩给你一条命令然后让你自己猜。

2. 安装前必须搞明白的四个概念

很多教程上来就让你下载安装包,然后一路Next,最后发现编译报错完全不知道哪出了问题。MinGW-w64的安装和Visual Studio最大的区别在于:VS的安装器帮你把所有细节都包好了,而MinGW-w64需要你自己做几个关键选择。这些选择直接影响你后面能不能顺利用上这个工具链。

2.1 MinGW和MinGW-w64有什么区别

你可能会在网上看到老教程教你装MinGW(原版),这个项目说实话已经处于半停滞状态了,32位支持为主,更新节奏非常慢。MinGW-w64是从MinGW衍生出来的分支,由社区维护,支持64位和32位目标,对C++11/14/17/20的支持完整得多,还引入了posix线程模型等特性。现在除非你有特殊兼容性需求,否则无脑选MinGW-w64就对了。

2.2 线程模型:posix还是win32

这是安装时最容易被忽略的选项。简单说,线程模型决定了GCC如何处理C++11之后的多线程特性。posix模型在内部使用Windows线程API,但对标准库提供了完整的std::thread支持,还能用上libstdc++的一些POSIX特性;win32模型则是纯Windows线程API,更轻量,但某些C++11多线程标准库功能无法使用。

我的建议很简单:不搞嵌入式交叉编译、不做极致体积优化,就选posix。现在几乎所有开源库和包管理器(比如vcpkg、Conan)都默认按posix模型编译,你用win32模型去链接别人编好的库,大概率会碰到符号不匹配的问题。我自己就踩过这个坑,后来全部统一成posix才消停。

2.3 异常处理模型:SEH还是SJLJ

Windows上GCC支持三种异常处理机制:SEH、SJLJ、DWARF。x86_64架构下,官方推荐的是SEH(结构化异常处理),它是Windows原生的异常机制,性能最好,没有额外的栈展开开销,而且其他编译器(MSVC、Clang)也都用它,兼容性最佳。SJLJ(setjmp/longjmp)可移植性好但性能差,DWARF只在32位下可用,64位不支持。

Windows平台64位目标选SEH,32位目标选DWARF或SJLJ,这是最稳妥的方案。下载时看到x86_64-posix-seh这种命名,x86_64指64位架构,posix指线程模型,seh指异常处理模型,三个信息全在名字里了。

2.4 解压版和安装版怎么选

MinGW-w64的常见分发形式有两种:一种是在线安装器(mingw-w64-install.exe),你选好参数后它在线下载;另一种是别人编译好的离线解压包(比如WinLibs、w64devkit)。在线安装器的问题是源往往在国外,国内网络环境下载经常卡死,而且安装速度感人。我个人更推荐直接用离线解压包,下载一个7z压缩包,解压到你想要的目录,配置好环境变量就完事,卸载也干净——直接删文件夹。

3. 下载MinGW-w64的正确姿势

3.1 去哪里下载

这里推荐几个下载源,按可靠程度排序。

首选是WinLibs(winlibs.com),这个项目专门提供MinGW-w64的自动构建版本,GCCl版本跟进很勤快,自带GDB调试器,还额外编译了make和ninja,省去你后面自己补工具的麻烦。唯一需要注意的是它提供了两个运行时版本:msvcrt和ucrt。Win10/11上建议选ucrt,性能更好,对C99/C11支持更完整,而且ucrt从Win10开始就是系统组件了,不用额外分发。

备选是w64devkit(github.com/skeeto/w64devkit),一个更加极简的版本,压缩包更小,还内置了Vim、Git等命令行工具,适合喜欢在终端里完成一切操作的开发者。

也可以直接去官方仓库的Release页面下载。不要用SourceForge上那个老的安装器,版本太旧了,很多新特性没有,而且下载体验一言难尽。

3.2 一个可以抄作业的下载选择

如果你用的是64位Windows 10或11,平时需要编译普通的C/C++程序,我建议你直接选WinLibs的ucrt版本,具体命名类似:

  • Win64 - UCRT - LLVM/Clang/LLDB/LLD - MinGW-w64 - GCC
  • 架构选x86_64,线程模型选posix,异常处理选seh

整个文件名翻译过来就是:64位、UCRT运行时、posix线程模型、SEH异常处理。这个组合在兼容性和性能之间取了一个非常均衡的点,这几年我用下来没有遇到过硬伤。

3.3 解压到哪个目录比较好

解压有个容易被忽略的原则:路径不要有空格,也不要有中文。虽然现在大部分工具都能处理带空格的路径,但CMake、Makefile、各种脚本对路径的处理方式千奇百怪,万一哪一步爆了,你排查的时间远远超过你多花两分钟选个干净路径的时间。

我习惯把工具链统一放在一个C:\dev\tools的目录下,解压后你会得到一个类似C:\dev\tools\mingw64的文件夹。这个目录就是MinGW-w64的根目录,里面会有binincludeliblibexec这些子文件夹。注意bin目录里面应该有gcc.exeg++.exegdb.exemingw32-make.exe这些可执行文件,没有的话说明你解压错了层级。

提示:如果解压后找不到bin目录,或者bin目录里没有gcc.exe,多半是你把整个外层文件夹都解压进去了。MinGW-w64的包根目录特征很明显——直接包含binincludelib这些文件夹。你只需要让环境变量指向那个包含bin的根目录即可。

4. 环境变量配置与验证

MinGW-w64本身是一个“绿色软件”,解压即用,但它不会自动加入PATH,你需要手动告诉系统去哪里找gcc.exe。这一步做不对,后面命令行里输gcc就会提示“不是内部或外部命令”。

4.1 手动配置PATH

Windows 11下右键“此电脑” →“属性”→“高级系统设置”→“环境变量”。在“系统变量”里找到Path,双击进去,点“新建”,添加你的MinGW-w64的bin目录路径,比如C:\dev\tools\mingw64\bin

为什么加bin而不是加整个MinGW-w64根目录?因为bin是存放可执行文件的地方,Windows的可执行文件搜索机制就是扫描PATH里每个目录,找这个目录下有没有对应用名的exe。你把根目录加进去,系统在根目录找不到gcc,依然没办法执行。

配置完后注意一点:如果你开着命令行窗口,PATH不会自动刷新。你需要关掉所有cmd、PowerShell窗口,重新开一个,再验证。我见过很多人配完环境变量,在同一个旧窗口里敲gcc,依然报错,就以为配置失败,其实只是窗口没刷新。

4.2 验证安装是否成功

开一个新的cmd或PowerShell窗口,依次执行下面几个命令:

gcc --version g++ --version gdb --version mingw32-make --version

正常的输出应该包含类似gcc (MinGW-W64 x86_64-ucrt-posix-seh) 13.2.0这样的版本信息。如果前三条都正常,说明编译器本体没问题;mingw32-make是Windows版的GNU Make工具,编译一些老项目会用到。

再执行一条交叉验证命令:

echo | gcc -dM -E - | findstr /i "WIN64 x86_64"

能输出_WIN64__x86_64__宏定义,说明这个编译器确实是64位目标。

4.3 命令行里验证C++标准支持

确认编译器能跑之后,顺手查一下支持的标准版本:

g++ -std=c++17 -E -x c++ /dev/null 2>nul && echo C++17 OK

或者更直接一点,写一个安安稳稳的小文件测试编译。命令行验证的主要目的是把“环境变量配置”和“编译本身”两件事解耦——环境变量对了,命令就能跑;编译能过,说明工具链完整。分开排查,思路更清晰。

5. 用一个真实的小项目走通编译流程

环境配置好之后,最好写个像样的程序试试,完整的编译链跑一遍,你才能确认这不是一个“只能打印版本号”的假环境。

5.1 写一个支持多线程的C++程序

下面这个例子我故意用到了C++11的线程库,为的是同时验证两件事:基本编译能力,以及前面选的posix线程模型是否工作正常。

新建一个文件main.cpp,内容如下:

#include <iostream> #include <thread> #include <vector> void worker(int id) { std::cout << "thread " << id << " running" << std::endl; } int main() { std::vector<std::thread> threads; for (int i = 0; i < 4; ++i) { threads.emplace_back(worker, i); } for (auto& t : threads) { t.join(); } std::cout << "all threads done" << std::endl; return 0; }

如果你当时选的是win32线程模型,这个程序编译大概率会直接报错,std::thread压根不可用。所以说下载时那个一步的选择,影响真的很大。

5.2 编译并运行

在项目目录下打开命令行,执行:

g++ -std=c++17 -Wall -Wextra -O2 main.cpp -o main.exe
  • -std=c++17:指定C++标准版本
  • -Wall -Wextra:开启警告,让编译器帮你找出潜在问题
  • -O2:开启优化
  • -o main.exe:指定输出文件名

然后运行:

.\main.exe

正常会看到4个线程的输出和最后的all threads done。如果这一步能过,说明你的MinGW-w64安装基本完备,日常编译需求都能满足了。

我还建议你用同样的方式编译一个包含多个.cpp文件的项目试试,比如把worker函数拆出去放到worker.cpp里,再写个worker.h,然后一条命令一起编译:

g++ -std=c++17 main.cpp worker.cpp -o main.exe

这样你能确认头文件搜索路径和单个编译单元的链接都没问题。

5.3 调试器的使用验证

有了GDB,才能算完整的开发环境。写一个会崩溃的程序,或者直接在GDB里设断点跑一遍:

gdb ./main.exe

在GDB交互界面里敲break main,然后run,程序就会停在main函数入口处。按next单步执行,print i查看变量值,continue继续运行,quit退出。GDB的Windows版本有时候会有一些终端兼容问题,如果遇到莫名卡顿,试试在GDB里先执行set pagination off

6. 再配一个Make工具:make还是mingw32-make

GCC本身只是一个编译器,它只负责把源代码变成目标文件和可执行文件。真正管理多文件编译、增量编译、自动化构建流程的是Make。MinGW-w64自带的make叫mingw32-make.exe,和Linux上的make命令用法基本一致,但可执行文件名不同。

如果你只是写写小项目、单文件编译,暂时用不上Make。但只要项目文件超过三五个,手敲编译命令就完全不现实了。我建议直接用内置的mingw32-make,在项目根目录写一个Makefile

CXX = g++ CXXFLAGS = -std=c++17 -Wall -Wextra -O2 TARGET = main.exe SRCS = main.cpp worker.cpp $(TARGET): $(SRCS) $(CXX) $(CXXFLAGS) $(SRCS) -o $(TARGET) clean: del $(TARGET) .PHONY: clean

然后执行:

mingw32-make

就能完成编译了。注意Windows上有多个make变体——MinGW自带的叫mingw32-make,如果你装了MSYS2,还有一个make命令,还有Chocolatey装的GnuWin32 make,不同版本之间行为有细微差异。最稳的做法:项目里你就固定用mingw32-make,别人要用的时候也明确告诉他们用哪个命令。

如果你对各种工具链的命名差异感到头大,有个更省心的选择:直接装MSYS2。MSYS2是一个完整的类Unix环境,包管理器pacman可以一条命令装GCC:

pacman -S mingw-w64-ucrt-x86_64-gcc

装出来和WinLibs一样是UCRT版本,而且版本更新更快、包更全。缺点是你得先适应pacman这套包管理思路。这篇文章主要讲MinGW-w64的解压即用方式,MSYS2适合想进一步折腾的读者,两条路并行不冲突。

7. 常见问题与排查技巧实录

这部分是我这些年实际遇到过的坑,每一个都让我花过不少时间排查。整理出来,你遇到可以直接对照处理。

7.1 “gcc不是内部或外部命令”

这是最常见的问题,原因基本只有三个:

  • PATH没配或者配错了。重新检查环境变量里Path有没有C:\dev\tools\mingw64\bin,注意是bin目录。
  • 改完环境变量没开新窗口。关掉当前cmd/PowerShell,重新打开一个。
  • 解压目录选错了层级。确认C:\dev\tools\mingw64\bin\gcc.exe真实存在。

快速验证路径是否正确,可以在PowerShell里执行:

Get-Command gcc

如果它能显示gcc.exe的完整路径,说明PATH配置成功。

7.2 编译时提示找不到头文件

编译C++程序时如果报错fatal error: iostream: No such file or directory,说明GCC没找到标准库头文件。先检查你是不是把所有文件都放在一个叫include的目录下却忘了告诉编译器;确认一下MinGW-w64目录结构是否正常,根目录下应该有includelib。如果目录结构正常但依然找不到,可能是你在命令行里设置了错误的CPLUS_INCLUDE_PATHC_INCLUDE_PATH环境变量,把它清掉再试。

7.3 链接时提示找不到某些系统库

比如报错cannot find -lwinpthread。这种情况多是因为你的项目里用了-lwinpthread这样的参数,但当前版本的MinGW-w64里这个库改名了或者合并进了其他库。先别急着怀疑环境坏了,查一下你的C:\dev\tools\mingw64\lib目录下有没有对应的.a文件,没有的话把链接参数去掉或者改成实际存在的库名。

更高级的排查手法是给GCC加-v参数,它会打印出完整的搜索路径和链接命令:

g++ -v main.cpp -o main.exe

这样你能看到GCC实际搜索了哪些目录、使用了哪些库,比盲猜快得多。

7.4 编译出来的程序在别人电脑上无法运行

MinGW-w64编译出的exe默认依赖一些Windows系统DLL(比如libgcc_s_seh-1.dlllibstdc++-6.dlllibwinpthread-1.dll),如果对方电脑上没有这些DLL(特别是Win7、Win8老系统),程序会直接报错“找不到libstdc++-6.dll”或者“无法启动此程序”。

解决办法有三种:

  1. 静态链接。编译时加-static -static-libgcc -static-libstdc++,把库直接嵌进exe里,文件会大一些,但目标机器不用装任何依赖。
  2. 把MinGW目录下的相关DLL一起拷贝到exe目录下。
  3. 用像UPX这样的工具压缩,同时解决体积和依赖问题(但有些杀软会误报)。

我通常的做法是:如果程序要给别人用,直接静态链接,省得一堆DLL拷来拷去。

7.5 PowerShell执行编译命令权限问题

有时候在PowerShell里执行gcc会提示“无法加载文件或者程序集”,这是因为PowerShell的执行策略限制了脚本运行,但不影响exe直接执行。如果你遇到奇怪的PowerShell报错,先用cmd试一下,能跑说明编译器没问题,问题出在终端环境配置上。

7.6 和Visual Studio的C++项目共存

一台机器同时装VS和MinGW-w64是完全没问题的,它们各自维护自己的编译链。但要注意的是,VS的命令行工具(cl.exe)和MinGW的文件名不冲突,可搜索路径里如果既有VS的工具又有MinGW的gcc,你在命令行里输cl会调用VS的编译器,输gcc会调用MinGW的编译器,各干各的。麻烦的是如果你用CMake生成项目,CMake默认找的编译器顺序可能会造成版本混乱。建议在CMake配置时明确指定编译器:

cmake -G "MinGW Makefiles" -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++

8. 额外推荐:顺手把VS Code也配好

既然你已经有了命令行工具链,下一步自然是配一个编辑器。我不太推荐新手直接用Vim或Emacs折腾,VS Code是绝大多数人最顺滑的选择:免费、轻量、插件生态成熟,而且对MinGW-w64的支持几乎是开箱即用的。

装好VS Code之后,安装C/C++扩展(由Microsoft发布)。然后新建一个工作目录,写好C++代码,按Ctrl+Shift+B,它会提示你配置构建任务。选择“C/C++: g++.exe 生成活动文件”,VS Code会自动生成一个.vscode/tasks.json,里面写好了编译命令。之后每次按Ctrl+Shift+B就能一键编译,F5能直接启动调试。

关于tasks.json有一个值得注意的细节:自动生成的编译命令默认不带-std=c++17这类参数,如果代码用了新标准特性会编译失败。你需要手动在tasks.json里的args数组中加上:

"args": [ "-fdiagnostics-color=always", "-g", "-std=c++17", "${file}", "-o", "${fileDirname}\\${fileBasenameNoExtension}.exe" ]

-g参数生成调试信息,F5调试必须依赖它。

再配一个c_cpp_properties.json,告诉VS Code你的编译器和标准:

{ "configurations": [ { "name": "Win64", "includePath": ["${workspaceFolder}/**", "C:/dev/tools/mingw64/include/**"], "defines": ["_DEBUG", "UNICODE", "_UNICODE"], "compilerPath": "C:/dev/tools/mingw64/bin/gcc.exe", "cStandard": "c17", "cppStandard": "c++17", "intelliSenseMode": "windows-gcc-x64" } ], "version": 4 }

这样写之后,VS Code的语法提示、跳转、自动补全就全部基于你真实使用的MinGW-w64了,不会再出现“VS Code编译能过但代码一路标红”的诡异问题。

9. 我看过无数教程,最后还是踩过的几个坑

最后来点掏心窝的经验总结,都是我在实际项目中一步步踩出来的,分享出来供参考。

第一,下载MinGW-w64别贪图“最新”。除非你有明确的需求要尝鲜新版本GCC(比如要测试C++23某个新特性),否则选上一个稳定版本即可。工具链的稳定性远比版本号有面子重要。WinLibs和官方仓库都会保留历史版本,找Release列表往下翻一点就能看到。

第二,线程模型能选posix就选posix,这不是偏执。很多第三方库(特别是Boost、Qt、OpenCV这些大块头)在Windows上用sched_yield、pthread接口做平台抽象,你要是win32模型,轻则编译不过,重则链接期报一堆undefined reference。犯不上为了一点性能差异去冒这个险。

第三,解压了MinGW-w64之后第一件事不是编译Hello World,而是先跑一遍GDB。我遇到过几次情况:编译器装好了,编译正常,但GDB一跑就报“Could not find version of Cygwin DLL”或者直接闪退。事后再补GDB麻烦得很,不如一开始就验证完整。

第四,别把MinGW-w64目录放在需要管理员权限才能写入的位置(比如C:\Program Files)。MinGW-w64虽然日常编译不需要管理员权限,但如果你用pacman(在MSYS2环境下)或者某些包管理器往里面装依赖,普通权限根本写不进去,找半天原因才发现是权限卡住了。

第五,想清楚你到底需要哪个构建系统。是只用GCC干编译,还是后面要接CMake、Ninja、Makefile。如果确定要搞CMake,建议把WinLibs里自带的make和ninja都留着,CMake生成构建系统的时候可用的生成器多一个,路就好走一分。

10. 结合个人习惯整理的最终推荐安装组合

如果你看完前面所有内容觉得信息量太大,不知道怎么选,那就按下面这套最省心的方案走:

  • 下载WinLibs的Win64 - UCRT - MinGW-w64 - GCC版本
  • 解压到C:\dev\tools\mingw64
  • C:\dev\tools\mingw64\bin加入系统PATH
  • 新开命令行,运行gcc --version验证
  • 写一个main.cpp测试std::thread编译
  • 有需要的话再配好make和VS Code

这一套下来,你在Windows上就拥有了一套完整的、不输Linux开发体验的GCC工具链。后面不管你是想编译开源项目、做算法竞赛、写Qt应用,还是搞嵌入式开发,这套环境都能扛住。我自己时至今日日常写C++还是用这套组合,VS Code配MinGW-w64,简单、干净、可控性强,没有VS那样动不动几GB的臃肿感。工具链这东西,适合自己工作流的才是最好的。希望这篇长文能帮你少走几步弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询