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

C++ 不同的MinGW-w64版本会中断DLL加载,c++,windows,dll,cross-compiling,mingw-w64,C++,Windows,Dll,Cross Compiling,Mingw W64,我有一个开源游戏项目,主要是在Ubuntu下开发的。最近我把它移植到了Windows,只是做了一些小的调整,然后为Windows构建了它,因为我只使用了跨平台的库和特性 为了构建它,最初我使用Ubuntu19.04存储库中的MinGW-w64进行交叉编译,效果非常好。这是它报告的版本: $ x86_64-w64-mingw32-g++-posix --version x86_64-w64-mingw32-g++-posix (GCC) 9.2-posix 20191008 Copyright (

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

为了构建它,最初我使用Ubuntu19.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.
当我更新到Ubuntu20.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-未找到入口点

在动态链接库«glome.exe路径»中找不到过程入口点ogg_page_bos

这里要注意的有趣点是:

  • 它将glome.exe视为一个DLL,不同于我在网上找到的所有错误实例,它将可执行文件放在标题上,但在消息正文中是一个实际的DLL
  • 所需符号可在配套文件libogg-0.dll中找到
  • 如果我在Linux上用Wine运行它,它就会工作
  • 如果我将二进制glome.exe与Ubuntu19.10中内置的glome.exe交换,它就可以工作
  • 两个版本(Ubuntu19.10和Ubuntu20.04)使用完全相同的编译器参数,由CMake生成
这是用于编译游戏文件之一的命令行(有许多文件,但所有文件都以相同的方式编译):

其中
cmakfiles/glome.dir/includes\u 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
其中
cmakfiles/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
中的相同参数生成

问题是:

  • 为什么Ubuntu20.04版本可以在Wine上运行,但不能在Windows上运行,而Ubuntu19.10版本可以在两者上运行
  • 如何修复Ubuntu20.04版本以在Windows上工作

在mingw-w64 IRC频道闲逛之后,那里的人建议我在dependency tracker中打开可执行文件,这突出了正在工作的二进制文件和已损坏的二进制文件之间的一个巨大区别:看起来符号要求从一个DLL“泄漏”到另一个不相关的DLL中

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

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


我不知道它以前为什么工作,很明显,在我使用的版本中,GNU
ld
出现了倒退。

您是否尝试使用MSVC(微软的编译器)进行编译?它需要更多的移植(因为它缺少GNU getopt),但是的,另一位开发人员成功地在Visual Studio中构建了它。它可以工作,类似于MinGW-w64 9.2。但相关性是什么?MingGW有一些缺陷,因为它基于GCC,GCC打算在类Unix系统上运行,而不是在Windows上。@Ivella getopt(来自)使用MinGW-w64构建。您应该构建并使用它。@AkibAzmain GCC是一个针对许多平台的非常通用的编译器,MinGW-w64 GCC是一个非常可靠的编译器,可以生成本机Windows可执行文件。提示:我总是将我的MSYS2 shell设置为将MinGW-w64放在搜索路径环境变量(如
PATH
)中的第一位>C_INCLUDE_PATH
CPLUS_INCLUDE_PATH
LIBRARY_PATH
(最后一个可能会使您免于此问题)。我没有使用MSYS32 shell,而是从Linux交叉编译。我从web下载了预编译库并手动指定了它们的路径。不要将MinGW链接到MSVC库。这通常会导致崩溃。例如,当使用MSVC malloc()从库函数和MSVC free()返回内容时更好的方法是让所有的东西都由同一个编译器构建。
../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