简体   繁体   English

不同的 MinGW-w64 版本会破坏 DLL 加载

[英]Different MinGW-w64 version breaks DLL loading

I have an open-source game project that was mostly developed under Ubuntu.我有一个主要是在 Ubuntu 下开发的开源游戏项目。 Recently I ported it to Windows, what consisted only in minor tweaks and then building it for Windows, since I only used cross-platform libraries and features.最近我将它移植到 Windows,只包括一些小的调整,然后为 Windows 构建它,因为我只使用跨平台库和功能。

To build it, initially I cross-compiled using MinGW-w64 from Ubuntu's 19.04 repositories, and it worked like a charm.为了构建它,最初我使用 Ubuntu 19.04 存储库中的 MinGW-w64 进行交叉编译,它的工作原理非常棒。 This is what it reports as the version:这是它报告的版本:

$ 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.

When I updated to Ubuntu 20.04, MinGW-w64 got a small bump in version number:当我更新到 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.

The update broke my build, as the executable generated by the new version of MinGW-w64 does not work.更新破坏了我的构建,因为新版本的 MinGW-w64 生成的可执行文件不起作用。 When executed on a Windows machine, it is unable to find the symbols from its DLL dependencies, and I get the following popup error:在 Windows 机器上执行时,无法从其 DLL 依赖项中找到符号,并且出现以下弹出错误:

未找到入口点

Which should translate to English version of the error message as (filling the variables):这应该翻译成英文版的错误消息(填充变量):

glome.exe - Entry Point Not Found glome.exe - 未找到入口点

The procedure entry point ogg_page_bos could not be located in the dynamic link library «path to glome.exe».过程入口点 ogg_page_bos 无法在动态链接库 «path to glome.exe» 中找到。

The interesting points to notice here are:这里需要注意的有趣点是:

  • it is regarding glome.exe as a DLL, different from all the instances of the error I find online, where it puts the executable on the title, but an actual DLL in the body of the message;它将 glome.exe 视为一个 DLL,不同于我在网上找到的所有错误实例,它将可执行文件放在标题上,但在消息正文中放置了一个实际的 DLL;
  • the needed symbol can be found on the companion file libogg-0.dll;所需的符号可以在配套文件 libogg-0.dll 中找到;
  • if I run it on Linux with Wine, it works;如果我用 Wine 在 Linux 上运行它,它就可以工作;
  • if I swap the binary glome.exe with the one built in Ubuntu 19.10, it works;如果我将二进制 glome.exe 与 Ubuntu 19.10 中内置的一个交换,它就可以工作;
  • both builds (Ubuntu 19.10 and Ubuntu 20.04) uses exactly the same compiler arguments, generated by CMake.两个版本(Ubuntu 19.10 和 Ubuntu 20.04)使用完全相同的编译器参数,由 CMake 生成。

This is the command line for the compilation of one of the files of the game (there are many files, but all are compiled in the same way):这是编译游戏文件之一的命令行(有很多文件,但都是用同样的方式编译的):

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

where CMakeFiles/glome.dir/includes_CXX.rsp contains only -I directives:其中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

The linking command for the executable is:可执行文件的链接命令是:

/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

where CMakeFiles/glome.dir/linklibs.rsp contains:其中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

Apart from the paths ( ubuntu-20.04-win-build vs ubuntu-19.10-win-build ), the compilation and linking commands are exactly the same, generated with the same parameters from the same CMakeLists.txt .除了路径( ubuntu-20.04-win-build vs ubuntu-19.10-win-build ),编译和链接命令完全相同,使用相同的参数从相同的CMakeLists.txt

The questions:问题:

  • Why Ubuntu 20.04 build works on Wine but doesn't work on Windows, while Ubuntu 19.10 build works on both?为什么 Ubuntu 20.04 构建在 Wine 上工作但在 Windows 上不起作用,而 Ubuntu 19.10 构建在这两个上都工作?
  • How to fix Ubuntu 20.04 build to work on Windows?如何修复 Ubuntu 20.04 版本以在 Windows 上运行?

After hanging out in mingw-w64 IRC channel, people there suggested me to open the executable in dependency tracker, which highlighted a big difference between the working and broken binaries: it looks like symbol requirements "leaked" from one DLL into another, unrelated, DLL.在 mingw-w64 IRC 频道闲逛后,那里的人建议我在依赖项跟踪器中打开可执行文件,这突出了工作二进制文件和损坏二进制文件之间的巨大差异:看起来符号要求从一个 DLL“泄漏”到另一个不相关的 DLL 中,动态链接库。

并排依赖行走

What led people there to take a closer look into the DLL import libraries.是什么促使那里的人们仔细研究了 DLL 导入库。 In particular, I was linking against some DLLs via their MSVC generated import libraries, namely: glew32.lib , OpenAL32.lib and SDL2.lib .特别是,我通过 MSVC 生成的导入库链接了一些 DLL,即: glew32.libOpenAL32.libSDL2.lib

It seems GNU ld has trouble handling import libraries from MSVC, and the fix was simply linking against the DLL files directly, in which case the symbol loading code is generated by ld itself (and this is actually a much better supported operation: always link against the .dll directly if possible, import libraries are not needed in GNU toolchain).似乎 GNU ld在处理来自 MSVC 的导入库时遇到了麻烦,修复只是直接链接到 DLL 文件,在这种情况下,符号加载代码是由ld本身生成的(这实际上是一个更好的支持操作:始终链接到如果可能,直接导入 .dll,GNU 工具链中不需要导入库)。

I don't know why it worked before, apparently there was a regression in GNU ld across the versions I used.我不知道为什么它以前有效,显然在我使用的版本中 GNU ld存在回归。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM