MinGW 那条路与 MSVC 只差三处:工具链开关、交叉前缀、导入库后缀。 但产物要多带三个 gcc 运行时 DLL,否则换台机器就起不来。
这一篇与 1.2.6 是同一件事的两条路,建议连着读。 读完这一篇,Windows 上的编译就全了;1.3 换到 Linux。
一、同一条流程,只差三处
环节 MSVC 路 MinGW64 路
工具链 --toolchain=msvc --toolchain=gcc 交叉前缀 不需要 --cross-prefix=x86_64-w64-mingw32- 导入库后缀 .lib .dll.a 调试信息 .pdb DWARF
--cross-prefix 是 MinGW 的特色:Windows 上的 MinGW 其实是一套交叉编译器,
真正的编译器叫 x86_64-w64-mingw32-gcc,前面那串是目标平台前缀。
为什么在 Windows 上也算交叉编译:因为 GCC 的老家是 Unix,它把自己当成「跑在某个系统上、
给另一个系统生成代码」的工具。在 MSYS2 里,宿主是 MSYS,目标是 Windows,所以叫交叉。
二、产物对照:三个文件名的差别
文件 MSVC MinGW64
导入库 avcodec.lib libavcodec.dll.a 运行时库 avcodec-60.dll avcodec-60.dll 工具链运行时 系统 VC 运行时 libgcc_s_seh-1.dll 等 编译命令 cl gcc
注意第三行:这是两条路唯一实质性的分发差别。MSVC 的产物在装了 VC 运行时的机器上直接能跑;
MinGW 的产物还要三个额外 DLL。
这三个 DLL 的名字要背下来,因为报错信息里出现的就是它们,而不是 avcodec:
libgcc_s_seh-1.dll、libstdc++-6.dll、libwinpthread-1.dll。
三、三个 DLL 怎么办:两条路
一条是编译时静态链进去,一条是发版时一起打给用户。 办法 怎么做 代价
静态链 LDFLAGS 加 -static-libgcc 体积大一点,分发简单 一起发 把三个 DLL 拷到 exe 旁 分发多三个文件,最可靠
只静态链 libgcc 不够。 如果你的程序里用了 C++ 标准库(比如 Qt),
libstdc++-6.dll 还得单独处理。最稳的做法是发版时把三个都带上。
本机这三个一个都没有,shutil.which 全查不到。
这也说明本机不是 MinGW 环境——否则它们会躺在 /mingw64/bin 或 /ucrt64/bin 里。
四、编完之后:先跑一次再发版
编完不要直接打包,先在干净的环境里试一次。 干净的判断办法:开一个只有系统 PATH 的 cmd,把 exe 放进去,双击。能起来说明依赖齐; 报缺 DLL,就把缺的那个名字记下来。 报错里的文件名 缺的是什么
avcodec-60.dll FFmpeg 库没拷过去 libgcc_s_seh-1.dll gcc 的异常处理运行时 libstdc++-6.dll C++ 标准库 libwinpthread-1.dll gcc 的线程运行时
这张表就是「MinGW 产物部署」的全部内容。 报哪个缺哪个,四个都齐了, 程序在任何一台 Windows 上都能起来。 MSVC 只有第一行。 这就是两条路在分发成本上的真实差距。
五、动手 Demo:MinGW64 工具链编 5.0+Libx264——和 MSVC 差在哪
本机没有 gcc,两条命令行一条也跑不了。 这一段做的是:拼命令、摆产物对照、查那三个 gcc 运行时 DLL 在不在。
line2 = ("./configure --toolchain=gcc --arch=x86_64 "
"--cross-prefix=x86_64-w64-mingw32- --enable-shared ...")
for f in ("libgcc_s_seh-1.dll", "libstdc++-6.dll", "libwinpthread-1.dll"):
print(f, shutil.which(f))
实跑输出:
--------------------------------------------------------------------
MinGW64 工具链编 5.0+Libx264——和 MSVC 差在哪
--------------------------------------------------------------------
**① 同一条流程,只有三处不一样**
环节 MSVC 路 MinGW64 路
--------------------------------------------------------------------------
工具链开关 --toolchain=msvc --toolchain=gcc
交叉前缀 无 --cross-prefix=x86_64-w64-mingw32-
导入库后缀 .lib .dll.a
**② 拼出来是这样**
`./configure --toolchain=gcc --arch=x86_64 --cross-prefix=x86_64-w64-mingw32- --e`
`nable-shared --disable-static --enable-gpl --enable-libx264`
**③ 两条路的产物摆一起看**
文件 MSVC MinGW64
-----------------------------------------------------------------------
导入库 avcodec.lib libavcodec.dll.a
运行时库 avcodec-60.dll avcodec-60.dll
工具链自带 DLL 无(用系统 VC 运行时) libgcc_s_seh-1.dll 等
调试信息 .pdb .debug(DWARF)
**④ 表格里第三行是最容易翻车的一格**
MinGW 编出来的 DLL 不是自给自足的:它默认动态链 `libgcc_s_seh-1.dll`、`libstdc++-6.dll`、
`libwinpthread-1.dll`。
本机这三个都没有,所以把 MinGW 产物拷到别的机器上,第一句报错往往是「找不到 libgcc_s_seh-1.dll」,
而不是「找不到 avcodec」。
`libgcc_s_seh-1.dll`:本机没有
`libstdc++-6.dll`:本机没有
`libwinpthread-1.dll`:本机没有
**⑤ 两个办法,二选一**
一是 configure 时加 `--disable-static` 之外再配 `LDFLAGS=-static-libgcc`,把 gcc 运行时静态进去;
二是发版时把三个 DLL 一起打给用户。**前者省事,后者可靠**,别两个都不做。
**⑥ 本机的实话**:`gcc` 与 `x86_64-w64-mingw32-gcc` 都不在 PATH,上面两条命令行一条也跑不了。
这一节给的是「参数怎么拼」,不是「跑出来什么」——参数可以背,输出只能在那台有编译器的机器上见。
三个 DLL 一条都找不到,本机不是 MinGW 环境。
有 MSYS2 的机器上,它们会出现在 /ucrt64/bin 或 /mingw64/bin 里。
30 秒实验
x86_64-w64-mingw32-gcc --version,看前缀在不在 PATH 上。objdump -p 你的.exe | grep DLL看一个 exe 依赖哪些 DLL。- 把编好的 exe 拷到一个空目录,双击,记下第一个报缺的 DLL 名字。
常见误区
- 以为 MinGW 产物是绿色的。 它默认要靠三个 gcc 运行时 DLL。
- 只静态链 libgcc。 用了 C++ 标准库的还得处理 libstdc++-6.dll。
- 在 MSYS 那层敲 configure。 出来的东西依赖 msys-2.0.dll,只能在这台机器上用。
自测三问(点开对答案)
1. MinGW 那条路与 MSVC 差哪三处? —— 工具链开关、交叉前缀、导入库后缀。前者要 --cross-prefix,产物是 .dll.a 而不是 .lib。 2. 为什么 MinGW 产物换台机器常报缺 DLL? —— 默认动态链三个 gcc 运行时。要么编译时静态链进去,要么发版时一起带上。 3. 报缺 libstdc++-6.dll 说明什么? —— 程序里用了 C++ 标准库,而那个 DLL 没跟过去。Qt 与 C++ 工程必须带上它。- ☐ (本节完,下一节 1.3 Linux 平台下编译 FFmpeg 5.0 源码)