不同的 MinGW-w64 版本会中断 DLL 加载

Different MinGW-w64 version breaks DLL loading

我有一个 open-source 游戏项目,主要是在 Ubuntu 下开发的。最近我将它移植到 Windows,只包含一些小的调整,然后为 Windows 构建它,因为我只使用了 cross-platform 库和功能。

为了构建它,最初我 cross-compiled 使用 Ubuntu 的 19.04 存储库中的 MinGW-w64,它的效果非常好。这是它报告的版本:

$ x86_64-w64-mingw32-g++-posix --version
x86_64-w64-mingw32-g++-posix (GCC) 9.2-posix 20191008
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

当我更新到 Ubuntu 20.04 时,MinGW-w64 的版本号出现了一个小问题:

$ x86_64-w64-mingw32-g++-posix --version
x86_64-w64-mingw32-g++-posix (GCC) 9.3-posix 20200320
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

更新破坏了我的构建,因为新版本的 MinGW-w64 生成的可执行文件无法运行。在 Windows 机器上执行时,它无法从其 DLL 依赖项中找到符号,并且出现以下弹出错误:

错误消息的英文版应翻译为(填充变量):

glome.exe - Entry Point Not Found

The procedure entry point ogg_page_bos could not be located in the dynamic link library «path to glome.exe».

这里需要注意的有趣点是:

这是游戏其中一个文件的编译命令行(文件很多,但都是同一个编译方式):

cd /home/lucas/glome/ubuntu-20.04-win-build/src/sdl && /usr/bin/x86_64-w64-mingw32-g++-posix   @CMakeFiles/glome.dir/includes_CXX.rsp -march=haswell -mtune=generic -Ofast -fno-fat-lto-objects -flto=12 -I/home/lucas/glome/windows-deps/opusfile/include/opus/ -I/home/lucas/glome/windows-deps/opus/include/opus/ -I/home/lucas/glome/windows-deps/libogg/include/ogg/ -I/home/lucas/glome/windows-deps/glew-2.1.0/include/ -I/home/lucas/glome/windows-deps/OpenAL-1.1-SDK/include -I/home/lucas/glome/windows-deps/libogg/include -I/home/lucas/glome/windows-deps/SDL2-2.0.12/include/ -I/home/lucas/glome/windows-deps/boost_1_72_0/ -g   -std=gnu++17 -o CMakeFiles/glome.dir/input.cpp.obj -c /home/lucas/glome/src/src/sdl/input.cpp

其中 CMakeFiles/glome.dir/includes_CXX.rsp 仅包含 -I 个指令:

-I/home/lucas/glome/src/src/common/. -I/home/lucas/glome/src/external/concurrentqueue -I/home/lucas/glome/ubuntu-20.04-win-build/src -I/home/lucas/glome/src/src/sdl

可执行文件的链接命令是:

/usr/bin/x86_64-w64-mingw32-g++-posix -march=haswell -mtune=generic -Ofast -fno-fat-lto-objects -flto=12 -I/home/lucas/glome/windows-deps/opusfile/include/opus/ -I/home/lucas/glome/windows-deps/opus/include/opus/ -I/home/lucas/glome/windows-deps/libogg/include/ogg/ -I/home/lucas/glome/windows-deps/glew-2.1.0/include/ -I/home/lucas/glome/windows-deps/OpenAL-1.1-SDK/include -I/home/lucas/glome/windows-deps/libogg/include -I/home/lucas/glome/windows-deps/SDL2-2.0.12/include/ -I/home/lucas/glome/windows-deps/boost_1_72_0/ -g   -Wl,--whole-archive CMakeFiles/glome.dir/objects.a -Wl,--no-whole-archive  -o glome.exe -Wl,--out-implib,libglome.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles/glome.dir/linklibs.rsp

其中 CMakeFiles/glome.dir/linklibs.rsp 包含:

../common/libcommon.a -lopengl32 -lglu32 -march=haswell -mtune=generic -Ofast -fno-fat-lto-objects -flto=12 -I/home/lucas/glome/windows-deps/opusfile/include/opus/ -I/home/lucas/glome/windows-deps/opus/include/opus/ -I/home/lucas/glome/windows-deps/libogg/include/ogg/ -I/home/lucas/glome/windows-deps/glew-2.1.0/include/ -I/home/lucas/glome/windows-deps/OpenAL-1.1-SDK/include -I/home/lucas/glome/windows-deps/libogg/include -I/home/lucas/glome/windows-deps/SDL2-2.0.12/include/ -I/home/lucas/glome/windows-deps/boost_1_72_0/ /home/lucas/glome/windows-deps/OpenAL-1.1-SDK/libs/Win64/OpenAL32.lib /home/lucas/glome/windows-deps/glew-2.1.0/lib/Release/x64/glew32.lib /home/lucas/glome/windows-deps/opusfile/lib/libopusfile.a /home/lucas/glome/windows-deps/opus/lib/libopus.dll.a /home/lucas/glome/windows-deps/libogg/lib/libogg.dll.a -L/home/lucas/glome/windows-deps/SDL2-2.0.12/lib/x64/ -lSDL2main -lSDL2 -static-libgcc -static-libstdc++ -Wl,-allow-multiple-definition -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32

除了路径(ubuntu-20.04-win-build vs ubuntu-19.10-win-build)之外,编译和链接命令完全相同,使用相同的参数从相同的CMakeLists.txt.[=24生成=]

问题:

在 mingw-w64 IRC 频道闲逛后,那里的人建议我在依赖跟踪器中打开可执行文件,这突出了工作二进制文件和损坏二进制文件之间的巨大差异:它看起来像是从一个 DLL 中“泄​​漏”的符号要求进入另一个不相关的 DLL。

是什么促使那里的人们仔细研究 DLL 导入库。特别是,我通过 MSVC 生成的导入库 link 对某些 DLL 进行了攻击,即:glew32.libOpenAL32.libSDL2.lib.

似乎 GNU ld 在处理从 MSVC 导入库时遇到问题,修复只是 link 直接针对 DLL 文件,在这种情况下,符号加载代码由 ld 本身(这实际上是一个更好的支持操作:如果可能,总是 link 直接针对 .dll,GNU 工具链中不需要导入库)。

我不知道为什么它以前能工作,显然我使用的版本在 GNU ld 中出现了回归。