【问题标题】:Different MinGW-w64 version breaks DLL loading不同的 MinGW-w64 版本中断 DLL 加载
【发布时间】:2021-01-12 20:29:28
【问题描述】:

我有一个开源游戏项目,主要是在 Ubuntu 下开发的。最近我把它移植到了 Windows 上,只做了一些小的调整,然后为 Windows 构建了它,因为我只使用了跨平台的库和功能。

为了构建它,最初我使用来自 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 - 未找到入口点

程序入口点 ogg_page_bos 无法位于动态链接库 «path to glome.exe» 中。

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

  • 它将 glome.exe 视为一个 DLL,与我在网上找到的所有错误实例不同,它将可执行文件放在标题上,但实际 DLL 在消息正文中;
  • 可以在配套文件 libogg-0.dll 中找到所需的符号;
  • 如果我用 Wine 在 Linux 上运行它,它可以工作;
  • 如果我将二进制 glome.exe 与 Ubuntu 19.10 中的内置文件交换,它可以工作;
  • 两个版本(Ubuntu 19.10 和 Ubuntu 20.04)使用由 CMake 生成的完全相同的编译器参数。

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

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生成相同的参数。

问题:

  • 为什么 Ubuntu 20.04 build 可以在 Wine 上运行,但不能在 Windows 上运行,而 Ubuntu 19.10 build 可以同时在这两种情况下运行?
  • 如何修复 Ubuntu 20.04 版本以在 Windows 上运行?

【问题讨论】:

  • 你试过用MSVC(微软的编译器)编译吗?
  • 它需要更多的移植(因为它缺少 GNU getopt),但是是的,另一个开发人员设法在 Visual Studio 中构建了它。它的工作原理类似于 MinGW-w64 9.2。但相关性是什么?
  • MingGW 存在一些错误,因为它基于 GCC,而 GCC 旨在在类 Unix 系统上运行,而不是在 Windows 上运行。
  • @Ivella getopt(来自software.frodo.looijaard.name/getopt/download.php)使用 MinGW-w64 构建。您应该构建并使用它。
  • @AkibAzmain GCC 是一个针对许多平台的非常通用的编译器,而 MinGW-w64 GCC 是一个非常可靠的编译器,可以生成本机 Windows 可执行文件。

标签: c++ windows dll cross-compiling mingw-w64


【解决方案1】:

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

是什么促使人们仔细研究 DLL 导入库。特别是,我通过它们的 MSVC 生成的导入库链接了一些 DLL,即:glew32.libOpenAL32.libSDL2.lib

似乎 GNU ld 无法处理来自 MSVC 的导入库,而修复只是直接链接到 DLL 文件,在这种情况下,符号加载代码是由 ld 本身生成的(这实际上是一个很大更好地支持操作:如果可能,始终直接链接到 .dll,GNU 工具链中不需要导入库)。

我不知道它以前为什么会起作用,显然我使用的各个版本在 GNU ld 中有一个回归。

【讨论】:

  • 提示:我总是将我的 MSYS2 shell 设置为将 MinGW-w64 内容放在搜索路径环境变量的首位,例如 PATHC_INCLUDE_PATHCPLUS_INCLUDE_PATHLIBRARY_PATH(这是最后一个可能已将您从这个问题中拯救出来)。
  • 我没有使用 MSYS32 shell,我是从 Linux 交叉编译的。我从网上下载了预编译的库并手动指定了它们的路径。
  • 不要将 MinGW 与 MSVC 库链接。这通常会导致崩溃。例如,当使用 MSVC malloc() 从库函数返回某些内容并使用 MSVC free() 清理它时。更好的是让所有东西都由同一个编译器构建。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多