简体   繁体   中英

Different MinGW-w64 version breaks DLL loading

I have an open-source game project that was mostly developed under 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.

To build it, initially I cross-compiled using MinGW-w64 from Ubuntu's 19.04 repositories, and it worked like a charm. 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:

$ 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. When executed on a Windows machine, it is unable to find the symbols from its DLL dependencies, and I get the following popup error:

未找到入口点

Which should translate to English version of the error message as (filling the variables):

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

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;
  • the needed symbol can be found on the companion file libogg-0.dll;
  • if I run it on Linux with Wine, it works;
  • if I swap the binary glome.exe with the one built in Ubuntu 19.10, it works;
  • both builds (Ubuntu 19.10 and Ubuntu 20.04) uses exactly the same compiler arguments, generated by 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:

-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:

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

The questions:

  • Why Ubuntu 20.04 build works on Wine but doesn't work on Windows, while Ubuntu 19.10 build works on both?
  • How to fix Ubuntu 20.04 build to work on 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.

并排依赖行走

What led people there to take a closer look into the DLL import libraries. In particular, I was linking against some DLLs via their MSVC generated import libraries, namely: glew32.lib , OpenAL32.lib and SDL2.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).

I don't know why it worked before, apparently there was a regression in GNU ld across the versions I used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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