尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Windows 上搭建类 Unix 开发环境:MSYS2 与 MinGW-w64 工具链配置指南

Windows 上搭建类 Unix 开发环境:MSYS2 与 MinGW-w64 工具链配置指南 1. 为什么 Windows 上还需要一个类 Unix 开发环境1.1 从一次编译报错说起很多在 Windows 上写 C/C 的朋友都遇到过这种场景代码在 Linux 服务器上跑得好好的拉到本地用 Visual Studio 一编译满屏的undefined reference、unistd.h: No such file or directory或者链接阶段报一堆pthread找不到。这不是代码写错了而是 Windows 原生工具链和 Unix 工具链在头文件、库命名、路径分隔符、换行符上的差异造成的。我自己最早做嵌入式交叉编译的时候就是被这个问题反复折磨。当时项目里既有 Linux 下的 Makefile又有 Windows 下的 Keil 工程两边代码要同步维护每次切换平台都要手动改一堆东西。后来接触到 MSYS2才算真正把 Windows 上的类 Unix 开发体验拉齐了。MSYS2 本质上是一个在 Windows 上运行的软件发行版它提供了一套 POSIX 兼容的运行时环境外加一个叫pacman的包管理器。你可以把它理解成Windows 里的一个小型 Linux 用户空间——但它不是虚拟机也不是 WSL而是直接跑在 Windows 内核上的原生程序。它最大的价值在于让你在 Windows 上也能用bash、make、gcc、pkg-config这些工具而且编译出来的程序既可以是依赖 MSYS2 运行时的类 Unix 程序也可以是纯 Windows 原生的通过 MinGW-w64 工具链。1.2 MSYS2、MinGW、GCC 三者到底是什么关系这三个词经常被混着用但它们的定位完全不同搞清楚这一点对后面的配置非常关键。GCC是编译器本身全称 GNU Compiler Collection支持 C、C、Fortran、Ada 等多种语言。它是一套工具链的核心但光有 GCC 还不够还需要配套的 binutils链接器、汇编器、运行时库、头文件等。MinGW全称 Minimalist GNU for Windows它的目标是把 GCC 工具链移植到 Windows 上让编译出来的程序直接依赖 Windows 系统 DLL比如msvcrt.dll不需要额外的 POSIX 兼容层。MinGW-w64 是 MinGW 的一个分支支持 64 位和 32 位是目前的主流选择。MSYS2则是一个完整的软件发行版它内部同时提供了两套工具链一套是msys前缀的依赖msys-2.0.dll模拟 POSIX 环境另一套是mingw64/mingw32前缀的生成原生 Windows 程序。你在 MSYS2 里装 GCC实际上装的是 MinGW-w64 版本的 GCC。用一个生活化的类比MSYS2 是一个商场GCC 是商场里卖的工具MinGW-w64 是这些工具的规格标准。你进商场买工具买到的就是符合 MinGW-w64 标准的 GCC。1.3 哪些人适合用 MSYS2不是所有人都需要 MSYS2。如果你只写纯 Windows 桌面程序用 Visual Studio 就够了MSVC 的调试体验和 Windows SDK 集成度是 MinGW 比不了的。但如果你符合下面任意一条MSYS2 会明显提升效率需要跨平台编译同一份代码要在 Linux 和 Windows 上都能构建使用 CMake、Autotools、Meson 这类构建系统它们默认假设有 Unix 工具做嵌入式开发需要arm-none-eabi-gcc、riscv64-unknown-elf-gcc这类交叉工具链想用pacman快速安装各种开发库而不是手动下载解压配环境变量需要在 Windows 上跑一些依赖 POSIX 接口的脚本或工具我个人的判断标准很简单如果你的项目里有configure脚本、Makefile、或者依赖pkg-config那 MSYS2 基本是 Windows 上的最优解。2. 安装前的准备与版本选择2.1 下载渠道与安装包类型MSYS2 的官方发布渠道是它的官网提供两种安装包一种是标准的图形化安装程序.exe另一种是免安装的压缩包.tar.xz或.sfx.exe自解压格式。我一般推荐用图形化安装程序因为它会自动处理开始菜单快捷方式和卸载信息省事。安装包分 64 位和 32 位两种。现在除非你有明确的 32 位需求比如维护老项目否则一律选 64 位。注意64 位的 MSYS2 里同时可以安装mingw32和mingw64两套工具链所以不用担心兼容性问题。提示下载时尽量从官方渠道获取避免第三方打包版本因为 MSYS2 的包管理依赖特定的目录结构和签名机制改过的安装包容易出问题。2.2 安装路径的选择原则安装路径这一项看起来不起眼但踩坑的人不少。MSYS2 的默认路径是C:\msys64我强烈建议保持这个默认值原因有三第一MSYS2 内部大量使用绝对路径路径里如果包含空格或中文某些老旧的构建脚本会解析失败。C:\msys64干净利落没有任何特殊字符。第二很多第三方工具比如某些 IDE 的自动探测逻辑会硬编码去C:\msys64找工具链你改了路径反而要手动配置。第三路径短意味着命令行里敲起来快而且不容易触发 Windows 的 260 字符路径长度限制。如果你 C 盘空间紧张想装到 D 盘那也尽量用D:\msys64这种简短路径别用D:\开发工具\msys2安装目录这种。2.3 首次启动与终端选择安装完成后开始菜单里会出现几个快捷方式名字分别是MSYS2 MSYS、MSYS2 MINGW64、MSYS2 MINGW32、MSYS2 UCRT64、MSYS2 CLANG64等。这些不是随便起的每个对应一个不同的环境区别在于PATH环境变量里默认包含哪个工具链目录。MSYS2 MSYS纯 MSYS 环境工具链是/usr/bin下的 msys 版本编译出来的程序依赖msys-2.0.dll。这个环境主要用来跑包管理和构建脚本不建议在这里编译最终产物。MSYS2 MINGW64PATH里优先包含/mingw64/bin用的是 MinGW-w64 的 64 位工具链生成原生 Windows 64 位程序。这是最常用的环境。MSYS2 UCRT64和 MINGW64 类似但 C 运行时用的是 Windows 10 之后的 Universal C RuntimeUCRT而不是老的msvcrt.dll。新项目建议优先用这个。MSYS2 CLANG64用 LLVM/Clang 工具链替代 GCC适合需要 Clang 特性的场景。我个人的习惯是日常开发用MSYS2 UCRT64遇到兼容性问题的老项目切回MSYS2 MINGW64。包管理操作统一在MSYS2 MSYS里做。3. 包管理与基础工具链安装3.1 pacman 的基本用法MSYS2 用的是pacman和 Arch Linux 是同一套包管理器。第一次打开终端先做两件事更新包数据库、升级已安装的包。pacman -Syu这条命令会先同步数据库然后升级所有包。注意如果升级过程中提示需要关闭终端那就关掉重新打开再执行一次pacman -Su完成剩余升级。这是 MSYS2 的一个特性核心运行时msys2-runtime更新后必须重启终端才能生效。常用的 pacman 命令我整理成了一张表方便查阅操作命令说明同步数据库并升级pacman -Syu最常用定期执行只升级已装包pacman -Su数据库已同步时用安装包pacman -S 包名可一次装多个空格分隔搜索包pacman -Ss 关键词支持正则查看已装包pacman -Q加-e只看显式安装的删除包pacman -R 包名加-s连带删除依赖清理缓存pacman -Sc释放磁盘空间查看包信息pacman -Si 包名看版本、依赖、大小注意pacman -Syu不要和-Sy 包名混用。单独-Sy只同步数据库不升级容易造成部分升级状态导致依赖断裂。要么完整升级要么直接装包pacman 会自动处理。3.2 安装 GCC 工具链在MSYS2 UCRT64或MSYS2 MINGW64终端里安装对应的工具链包。以 UCRT64 为例pacman -S mingw-w64-ucrt-x86_64-gcc这一条命令会连带安装binutils、gcc-libs、crt、headers、winpthreads等依赖。装完之后验证gcc --version g --version如果能看到版本号说明工具链就位了。这里有个细节gcc和g是两个独立的包装gcc不一定带g。如果你要写 C得额外装pacman -S mingw-w64-ucrt-x86_64-gcc实际上mingw-w64-ucrt-x86_64-gcc这个包已经包含了g但有些精简包比如gcc-libs只带运行时库。保险起见装完检查一下g --version能不能跑。3.3 常用配套工具光有编译器还不够实际开发中还需要一堆辅助工具。我列一份必装清单pacman -S mingw-w64-ucrt-x86_64-toolchaintoolchain是一个元包meta package它会一次性把 GCC、GDB、binutils、make、pkg-config 等常用工具全装上。这是最省事的方式新手直接装这个就行。如果你想要更精细的控制可以单独装mingw-w64-ucrt-x86_64-gdb调试器mingw-w64-ucrt-x86_64-cmakeCMake 构建系统mingw-w64-ucrt-x86_64-ninjaNinja 构建后端比 make 快mingw-w64-ucrt-x86_64-pkg-config库依赖查询工具mingw-w64-ucrt-x86_64-makeGNU make另外MSYS 环境本身也建议装一些基础工具比如git、wget、unzip、tar、vim这些在MSYS2 MSYS终端里装pacman -S git wget unzip tar vim3.4 环境变量的处理MSYS2 的各个终端快捷方式已经帮你配好了PATH所以正常情况下不需要手动改系统环境变量。但如果你想让 Windows 的cmd或 PowerShell 也能直接用gcc那就得把C:\msys64\ucrt64\bin或C:\msys64\mingw64\bin加到系统PATH里。我的建议是不要加。原因很简单MSYS2 的工具链和 Windows 原生工具比如某些软件自带的libstdc-6.dll容易冲突。你在cmd里跑gcc加载的可能是别的软件目录下的旧版本 DLL导致莫名其妙的崩溃。要用 MSYS2 工具链就老老实实开 MSYS2 终端。如果确实需要在外部终端调用更稳妥的做法是在cmd里临时设置set PATHC:\msys64\ucrt64\bin;%PATH%这样只对当前会话生效不会污染全局环境。4. 编译器配置与实战验证4.1 验证工具链是否正常工作装完工具链写个最简单的程序验证一下。新建hello.c#include stdio.h int main(void) { printf(Hello from MSYS2 UCRT64\n); return 0; }编译并运行gcc hello.c -o hello.exe ./hello.exe如果输出正常说明工具链没问题。再用file命令看一下产物类型file hello.exe应该显示PE32 executable (console) x86-64, for MS Windows。这说明生成的是原生 Windows 程序不依赖 MSYS2 运行时。4.2 静态链接与动态链接的选择默认情况下MinGW-w64 编译出来的程序会动态链接libgcc_s_seh-1.dll、libstdc-6.dll、libwinpthread-1.dll这几个运行时库。这意味着你把hello.exe拷到别的电脑上如果那台电脑没有这些 DLL程序就跑不起来。解决办法是静态链接gcc hello.c -o hello.exe -static或者只静态链接 GCC 运行时保留系统库动态链接gcc hello.c -o hello.exe -static-libgcc -static-libstdc我一般推荐后者因为完全静态链接会让可执行文件体积膨胀不少而且某些系统 API 的静态链接可能有问题。-static-libgcc -static-libstdc只把 GCC 自己的运行时打进去体积增加可控兼容性也好。对于 C 项目还要注意异常处理和线程模型。MinGW-w64 默认用 SEHStructured Exception Handling异常模型和 POSIX 线程模型。如果你链接的第三方库是用别的模型编译的可能会出问题。检查方法gcc -v 21 | grep Thread model输出应该是posix。如果是win32说明你用的是老版本工具链建议升级。4.3 多版本工具链共存有时候你需要同时维护多个项目一个用 GCC 12一个用 GCC 14。MSYS2 的包管理默认只保留最新版但你可以通过安装不同前缀的包来实现共存。比如同时装mingw-w64-ucrt-x86_64-gcc和mingw-w64-clang-x86_64-clang然后在不同终端里切换。更彻底的做法是用update-alternatives机制但 MSYS2 对这个支持有限。我的经验是直接用不同的终端环境隔离UCRT64 一套、MINGW64 一套、CLANG64 一套互不干扰。需要哪个就开哪个终端比手动切PATH靠谱得多。4.4 与 IDE 的集成如果你用 VS Code装C/C扩展后在.vscode/c_cpp_properties.json里配置编译器路径{ configurations: [ { name: MSYS2-UCRT64, includePath: [ ${workspaceFolder}/**, C:/msys64/ucrt64/include/** ], compilerPath: C:/msys64/ucrt64/bin/gcc.exe, cStandard: c17, cppStandard: c20, intelliSenseMode: windows-gcc-x64 } ], version: 4 }注意路径用正斜杠/VS Code 在 Windows 上也能识别。intelliSenseMode一定要设成windows-gcc-x64否则代码补全会用 MSVC 的规则导致一些 GCC 特有的语法报错。如果用 CLion 或 Qt Creator它们通常能自动探测 MSYS2 工具链但探测到的可能是 MINGW64 而不是 UCRT64。手动指定工具链目录为C:\msys64\ucrt64即可。5. 常见问题与排查技巧实录5.1 安装卡住或下载缓慢pacman -Syu卡在某个包下载不动是国内用户最常见的问题。原因是 MSYS2 默认的镜像源在国外网络不稳定。解决办法是换国内镜像源。编辑/etc/pacman.d/mirrorlist.mingw32、/etc/pacman.d/mirrorlist.mingw64、/etc/pacman.d/mirrorlist.ucrt64、/etc/pacman.d/mirrorlist.msys这几个文件在文件开头加上国内镜像地址。比如Server https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/ucrt64/ Server https://mirrors.ustc.edu.cn/msys2/mingw/ucrt64/每个文件对应不同的仓库mingw64文件里放 mingw64 的地址ucrt64文件里放 ucrt64 的地址别搞混了。改完之后执行pacman -Syy强制刷新数据库。提示镜像源不是越多越好pacman 会按顺序尝试。把最快的放最前面后面的作为备份。如果某个源同步滞后可能导致包版本对不上这时候临时注释掉它再刷新。5.2 编译时报 cannot find -lxxx链接阶段找不到库通常有三种原因库没装、库路径没配、库名写错。先确认库是否安装pacman -Qs 库名关键词比如找不到-lssl就搜pacman -Ss openssl找到对应的mingw-w64-ucrt-x86_64-openssl装上。如果库装了还是找不到用pkg-config查一下pkg-config --libs openssl pkg-config --cflags openssl把输出的-L和-I参数加到编译命令里。更规范的做法是在 Makefile 或 CMakeLists 里用pkg_check_modules自动获取。5.3 中文乱码问题MSYS2 终端默认用 UTF-8 编码但 Windows 控制台默认是 GBK代码页 936。这导致两个问题一是终端里显示中文乱码二是程序输出中文到控制台时乱码。终端显示问题可以在 MSYS2 的终端设置里把字符集改成 UTF-8。程序输出问题需要在程序里设置#include windows.h #include stdio.h int main(void) { SetConsoleOutputCP(CP_UTF8); printf(中文测试\n); return 0; }或者在编译时定义-DUNICODE -D_UNICODE用宽字符 API。我一般推荐前者改动小兼容性好。5.4 路径转换的坑MSYS2 里有个自动路径转换机制当你把/c/Users/xxx这样的路径传给原生 Windows 程序时MSYS2 会自动转成C:\Users\xxx。这个机制大部分时候是好事但有时候会帮倒忙。比如你写了个脚本参数里有个/helpMSYS2 可能把它转成C:\msys64\help导致程序报错。解决办法是设置环境变量export MSYS2_ARG_CONV_EXCL*这会禁用所有参数转换。或者只排除特定前缀export MSYS2_ARG_CONV_EXCL--prefix;/help5.5 常见问题速查表现象可能原因解决方法pacman卡住不动镜像源慢换国内镜像pacman -Syygcc: command not found终端环境选错用 MINGW64/UCRT64 终端别用 MSYS链接报undefined reference库没装或顺序错装库调整-l顺序被依赖的放后面程序拷到别的电脑跑不起来缺运行时 DLL加-static-libgcc -static-libstdc中文输出乱码控制台代码页不对SetConsoleOutputCP(CP_UTF8)make报路径错误路径含空格或中文项目移到纯英文无空格路径编译极慢没用并行构建make -j$(nproc)或cmake --build . -jpkg-config找不到包.pc文件路径没配设PKG_CONFIG_PATH指向对应lib/pkgconfig5.6 几个我踩过的坑第一个坑在MSYS2 MSYS终端里编译 C 程序结果链接了一堆 msys 版本的库生成的 exe 依赖msys-2.0.dll拷到别的机器上直接报错。后来才明白编译产物一定要在 MINGW64 或 UCRT64 终端里做MSYS 终端只用来跑包管理和脚本。第二个坑pacman -Syu升级到一半断电导致包数据库损坏。恢复方法是删掉/var/lib/pacman/db.lck锁文件然后pacman -Syy重新同步。如果还不行就得重装 MSYS2 了。所以升级前最好确保电源稳定。第三个坑用 CMake 配置项目时CMake 自动找到了C:\Program Files\Git\usr\bin下的sh.exe而不是 MSYS2 的。这会导致构建脚本行为异常。解决办法是在 CMake 命令里显式指定cmake -G Ninja -DCMAKE_SHC:/msys64/usr/bin/sh.exe ..或者在 CMakeLists 开头加set(CMAKE_SH C:/msys64/usr/bin/sh.exe)。6. 进阶配置与效率提升6.1 终端美化与效率工具MSYS2 自带的 mintty 终端功能比较基础。如果你想要更好的体验可以装zsh和oh-my-zshpacman -S zsh sh -c $(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)不过oh-my-zsh的安装脚本依赖网络国内可能拉不下来。替代方案是用zsh加zinit或者手动配置。我自己的.zshrc就几十行够用了没必要上重型框架。另外推荐装fzf模糊查找、ripgrep快速搜索、bat带语法高亮的 cat、fd快速 findpacman -S fzf ripgrep bat fd这些工具在 MSYS2 里都能直接装用起来和 Linux 上一样。6.2 用 makepkg 构建自定义包MSYS2 支持makepkg可以自己写 PKGBUILD 构建包。这对于维护内部工具链很有用。比如你想把公司内部的某个库打包成 pacman 包方便团队安装就可以写个 PKGBUILDpkgnamemycompany-lib pkgver1.0.0 pkgrel1 pkgdescInternal library arch(x86_64) urlhttps://example.com license(MIT) depends(mingw-w64-ucrt-x86_64-gcc-libs) source($pkgname-$pkgver.tar.gz) sha256sums(SKIP) build() { cd $srcdir/$pkgname-$pkgver ./configure --prefix/ucrt64 make } package() { cd $srcdir/$pkgname-$pkgver make DESTDIR$pkgdir install }然后makepkg -si就能构建并安装。这套流程和 Arch Linux 完全一致会 Arch 的话零学习成本。6.3 交叉编译环境搭建做嵌入式开发的话MSYS2 也能装交叉工具链。比如 ARM Cortex-Mpacman -S mingw-w64-ucrt-x86_64-arm-none-eabi-gcc pacman -S mingw-w64-ucrt-x86_64-arm-none-eabi-binutils pacman -S mingw-w64-ucrt-x86_64-arm-none-eabi-newlib装完之后就能用arm-none-eabi-gcc编译 STM32 之类的固件了。配合openocd还能直接烧录调试pacman -S mingw-w64-ucrt-x86_64-openocd这套组合我在 STM32F103 的项目上用过比装 Keil 或者 IAR 轻量得多而且构建脚本可以完全用 Makefile 管理方便做 CI。6.4 与 WSL 的取舍有人会问既然有 WSL为什么还要用 MSYS2这两者定位不同。WSL 是一个完整的 Linux 内核跑的是真正的 Linux 二进制适合需要完整 Linux 环境的场景比如跑 Docker、systemd 服务。但 WSL 的文件系统跨平台访问性能差Windows 和 Linux 之间读写文件有开销。MSYS2 是原生 Windows 程序文件系统就是 NTFS没有跨平台开销。编译速度通常比 WSL 快尤其是涉及大量小文件读写的时候。而且 MSYS2 生成的 exe 可以直接在 Windows 上跑不需要额外的运行时。我的选择是纯 Windows 开发用 MSYS2需要 Linux 特有功能比如特定内核版本、Docker用 WSL。两者可以共存互不影响。6.5 备份与迁移MSYS2 的配置和已装包列表可以导出方便换机器时快速恢复pacman -Qqe packages.txt在新机器上pacman -S --needed - packages.txt配置文件.bashrc、.zshrc、.gitconfig等放在用户目录下直接拷过去就行。整个C:\msys64目录理论上也可以直接拷贝但要注意路径依赖问题如果新机器上路径不同某些包的脚本会失效。所以还是推荐用包列表重建的方式。7. 我个人的使用体会用了几年 MSYS2最大的感受是它把 Windows 上的开发体验拉到了和 Linux 接近的水平但又没有 WSL 那种隔了一层的感觉。编译速度快、工具链完整、包管理方便这三点是它最核心的价值。不过它也不是没有缺点。pacman 的包更新比较激进有时候升级完某个库老项目就编不过了。我的应对策略是生产环境锁定版本用pacman -U装特定版本的包而不是无脑-Syu。另外MSYS2 的文档相对分散很多问题得靠搜索和试错解决这也是我写这篇总结的原因——把踩过的坑集中记下来下次遇到直接查。最后分享一个小技巧如果你经常需要在不同工具链之间切换可以写几个 alias 放在.bashrc里alias ucrtexport PATH/ucrt64/bin:$PATH alias mingwexport PATH/mingw64/bin:$PATH alias msysexport PATH/usr/bin:$PATH这样在同一个终端里就能快速切换工具链不用反复开关窗口。当然切换后记得hash -r清一下命令缓存否则 shell 可能还在用旧的路径。
返回列表