Wine cannot load DLLs even though the directory is added to PATH - c++

I am trying to cross-compile Windows software on Linux using mingw32-w64 and running it with wine. However wine cannot load the libstdc++-6.dll library file. I searched online and found out that you have to put the directory that contains the DLL file into the path registry. In my case, that directory is Z:\bin\i686-w64-mingw32\bin.
Then I tried to run the compiled file by using wine executable.exe and the output is:
0100:err:module:import_dll Loading library libstdc++-6.dll (which is needed by L"Z:\\home\\sunnymonster\\dev\\c++\\opengl-tests\\cmake-build-debug\\opengl_tests.exe") failed (error c000007b).
0100:err:module:LdrInitializeThunk Importing dlls for L"Z:\\home\\sunnymonster\\dev\\c++\\opengl-tests\\cmake-build-debug\\opengl_tests.exe" failed, status c0000135
I have verified that I am using the correct wine prefix.
Additional information:
Linux distro: Manjaro Linux 21.2.5
Linux kernel: 5.16.14-1

There're multiple approaches. First, let's formalize the problem:
$ cat test.cpp
#include <iostream>
int main() { std::cout << "hello" << std::endl; }
$ i686-w64-mingw32-g++ test.cpp -o a && WINEDEBUG=-all,err+module wine ./a.exe
0024:err:module:import_dll Library libgcc_s_dw2-1.dll (which is needed by L"Z:\\tmp\\a.exe") not found
0024:err:module:import_dll Library libstdc++-6.dll (which is needed by L"Z:\\tmp\\a.exe") not found
0024:err:module:LdrInitializeThunk Importing dlls for L"Z:\\tmp\\a.exe" failed, status c0000135
Solutions:
Link the core libraries statically:
$ i686-w64-mingw32-g++ test.cpp -o a -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic
$ WINEDEBUG=-all,err+module wine ./a.exe
hello
Use WINEPATH env. variable to tell wine the additional paths to load dlls from. In the example I pass it the location with mingw dlls that wine complains about. It may be different on your system, you might find it by asking package manager to list files in mingw-g++/gcc packages (whatever it's called on your system). Multiple paths should be separated by semicolon.
$ i686-w64-mingw32-g++ test.cpp -o a
$ WINEDEBUG=-all,err+module WINEPATH=/usr/i686-w64-mingw32/sys-root/mingw/bin/ wine ./a.exe
hello
Install a Windows version of MinGW, and then use it to compile the app. However, from what I remember, if you want to distribute the executable produced, you still need to either statically link against MinGW libs, or provide them together with the binary. So the only difference to point 1 is that the binary should work under your WINEPREFIX with no modifications.
Using wineg++. I mention it solely for completeness, I think it's the least useful solution. It produces a Linux file, which in itself might be okay, one could use that for debugging. However, in my tests, I didn't manage to makewineg++ link against a dll, even though mingw links to the same dll without a problem. It seems to link against .so files instead, even though the application you build with it can load .dll files dynamically. Odd utility.
$ wineg++ test.cpp -o a
$ WINEDEBUG=-all,err+module wine ./a.exe
hello

Related

How to link to shared object library in msys2?

I have some c++ code in msys2 that I am trying to link dynamically to show how a dynamic link library works.
In linux, showing the call is no problem. stepping in gdb, we can watch the call go through the jump vector, eventually landing in the desired function.
But in msys2, they wanted to eliminated dlls and all the libraries I can find are .dll.a, I think they are really static libraries.
I build a trivial little function like this:
#include <cstdint>
extern "C" {
uint64_t f(uint64_t a, uint64_t b) {
return a + b;
}
}
compiling in the makefile with:
g++ -g -fPIC -c lib1.cc
g++ -g -shared lib1.o -o libtest1.so
When I run the file utility, it says that:
libtest1.so: PE32+ executable (DLL) (console) x86-64, for MS Windows
When I compile the code using it:
g++ -g main.cc -ltest1 -o prog
The error is -ltest1 no such file or directory.
MinGW uses the .dll extension for shared libraries, not .so.
lib??.dll.a is an import library, a shim that will load the corresponding lib??.dll at runtime.
At some point in time, you couldn't link .dlls directly, and had to link .dll.as instead. The modern MinGW can link .dlls directly, so you shouldn't need to use import libraries anymore.
-ltest1 no such file or directory
Wouldn't you get the same error on Linux? You have to specify the library search path with -L. -ltest1 needs either libtest1.a or libtest1.dll.a or libtest1.dll (perhaps some other variants are checked too).
The reason your linker cannot find the library is because your current working directory is not in the search path for libraries. Add -L. to your linking command.
It is untrue that MSYS2 "wanted to eliminate DLLs". Just run ls /mingw64/bin/*.dll and you will see plenty of DLLs (assuming you have some MINGW64 packages installed). The .dll.a files used for linking are called import libraries.

Error loading SDL2 shared libraries while executing program on another pc

I'm trying to compile a program i made using SDL2 to work on others computers (or testing VM in this case).
I've been compiling it with what i think are the correct flags, e.g. g++ main.cpp -o main -lSDL2, however when i try executing it on another Ubuntu installation i get this error.
error while loading shared libraries: libSDL2-2.0.so.0: cannot open shared object file: No such file or directory
From my understanding it's not a problem in my compiling but with how i expect it to work on another Linux installation; I've cross-compiled (using mingw32) and tested it (using a freshly installed VM) on Windows adding the correct dlls with the exe (seems to work fine) and I was expecting for it to work in a similar fashion.
What's the standard in this cases? Should i write a setup scripts to install the library dependencies on the target machine? Is there another way I'm not aware of? I've never released an application for Linux (nor Windows) and I'm struggling to find the resources to do things "the right way".
Thanks for everyone suggestions, I ended up settling for the easy way, compiling the "easy to install" libraries dynamically e.g.-lSDL2 and the others statically (checked the licenses and it should be fine) like so:
g++ main.cpp -o main -Wl,-Bdynamic -lSDL2 -lSDL2_image -lSDL2_ttf -Wl,-Bstatic -lSDL2_gfx -static-libgcc -static-libstdc++
I'll put in my documentation how to install the required SDL2 libraries.
I am not sure how familiar you are with pkg-config, but the output for sdl2 is this:
-D_REENTRANT -I/usr/include/SDL2 -lSDL2
This was found from running this:
pkg-config --cflags --libs sdl2
Basically, you need to point to where SDL2 is located BEFORE you actually link to it.
The tool pkg-config is designed to tell you the information you need when you want to link to a package in Linux. You were linking with the library, but you forgot to tell GCC where the library is located.
If you want to compile you code, try this:
g++ main.cpp -o runme `pkg-config --cflags --libs sdl2`
This will automatically grab all of the flags that you need to compile with SDL2 included.
Oh, and you should note, ORDER MATTERS WHEN ADDING FLAGS AND LIBRARIES!!!
There are many questions on SO where the order of compiler options caused all of the problems. Do not be like those people. I suggest you search SO for more info on that.

Executing cross-compiled C++ program using Boost on Raspberry Pi

I have built a GCC cross toolchain for the RPi and can cross-compile C++ source and successfully run it after copying the executable to the RPi.
Next I built the Boost libraries targeting ARM, using the cross toolchain. I can successfully build and link C++ source to those Boost libraries using the cross toolchain on my PC.
I then copied the program, dynamically linked to Boost, to the RPi and copied all built libraries into /usr/local/lib on the Pi. However, executing fails:
$ ./my_program
./my_program: error while loading shared libraries: libboost_system.so.1.60.0: cannot open shared object file: No such file or directory
Again, this library, libboost_system.so.1.60.0, exists in /usr/local/lib.
I also tried
export LD_LIBRARY_PATH='/usr/local/lib'
but that doesn't change anything. What am I doing wrong?
EDIT:
I build all source files like this (rpi-g++ is a symlink to my cross-compiler):
rpi-g++ -c -std=c++1y -Wall -Wextra -pedantic -O2 -I /path/to/cross/boost/include *.cpp
rpi-g++ -o myprog *.o -L /path/to/cross/boost/lib/ -lboost_system -pthread
EDIT 2:
When linked with
rpi-g++ -o myprog *.o -L /path/to/cross/boost/lib/ -rdynamic -lboost_system -pthread
the problem remains the same. I have checked and verified everything suggested by Technaton as well. Strangely, ldd insists that the created executable is "not a dynamic executable" (checked that on my PC and on the RPi), which doesn't make sense to me.
There are several things you can check. I've posted a complete check list here, but judging from your linker command line, number 5 is probably the culprit.
Check that your library and your program are correctly build for the target architecture. You can verify that by using file ./myprog and file libboost_system.so.1.60.0.
Make sure that you have copied the actual shared object, and not a link to it.
Ensure that the shared object file's permissions are sane (0755).
Run ldconfig -v and check that your shared object file is picked up. Normally, /usr/local/lib is in the standard library search path, and LD_LIBRARY_PATH is not required.
Make sure that your program is actually dynamically linked by running ldd ./myprog. Judging from your linker command line, that is the problem: You're missing -rdynamic.
Check the paths returned from ldd: If you have linked with rpath, the library search path might be screwed up. Try again without -rpath.

Cygwin G++ linker (ld.exe) on Windows 7 cannot find libc.so.6 and other library files

I am using g++ in a cygwin terminal to link several c object files and c++ object files together into a single shared executable. The linker tells me that there are several libraries it cannot find. However, I can list them, using the locations where the linker states that it is looking for them:
g++ -g -o myProg.so *.o -shared
c:/cygwin/bin/../lib/gcc/x86_64-vityan-linux-gnu/4.6.0/../../../../x86_64-vityan-linux-gnu/bin/ld.exe: *cannot find /lib/libc.so.6*
c:/cygwin/bin/../lib/gcc/x86_64-vityan-linux-gnu/4.6.0/../../../../x86_64-vityan-linux-gnu/bin/ld.exe: *cannot find /x86_64-vityan-linux-gnu/lib/libc_nonshared.a*
c:/cygwin/bin/../lib/gcc/x86_64-vityan-linux-gnu/4.6.0/../../../../x86_64-vityan-linux-gnu/bin/ld.exe: *cannot find /lib/ld-linux-x86-64.so.2*
collect2: ld returned 1 exit status
$ ls /lib/libc.so.6
/lib/libc.so.6
$ ls /x86_64-vityan-linux-gnu/lib/libc_nonshared.a
/x86_64-vityan-linux-gnu/lib/libc_nonshared.a
$ ls /lib/ld-linux-x86-64.so.2
/lib/ld-linux-x86-64.so.2
I have tried renaming the .so files to .dll with no success.
I have tried to use the g++ switch '--sysroot' ( --sysroot=/cygdrive/c/cygwin/) with no success.
I have tried adding the g++ switch '-B /cygdrive/c/cygwin/lib/' with no success.
The thing that's really got me confused is that I did this same thing on a similar project about 6 months ago - no issues. And, the system clearly shows that the libraries are there.
What is missing that ld.exe needs to find these files?
I ran a quick analysis of what packages I had installed in Cygwin. I had several of the mingw g++ toolchain packages as well (which don't get used), and a bunch of other stuff. I only use Cygwin for a few specific projects, so I reinstalled: removed all of the other g++ toolchain items, and just installed the cygwin gcc 64 bit toolchain packages. Project now compiles without issue. Closing question.

Copy and pasting .so file doesn't work with linker

I compiled and built the casablanca c++ rest library in my home directory where my absolute path to the necessary .so file was /home/dev/casablanca/Release/build.release/Binaries/libcpprest.so. What I wanted to do was to simply cp and past that .so file to /usr/lib/.. path to default lib search ../ so that I could easily link it with the following command:
g++ index.cpp -I/home/dev/casablanca/Release/include -lcpprest -std=c++11
which compiled fine, but when I ran ./a.out I got the typical runtime error:
couldn't load shared library: libcpprest.so
even after adding the default path of libcpprest.so to LD_LIBRARY_PATH.
However everything worked just fine if I linked the directory where the binary was originally created at:
// ./a.out runs just fine
g++ index.cpp -I/home/dev/casablanca/Release/include \
-L/home/dev/casablanca/Release/build.release/Binaries -lcpprest -std=c++11
I'm guessing that the reason why I can't simply move the .so object where I want to add it is somehow the compiler keeps references to it somehow. How can I install this binary in a different path?
I did compile casablanca on my linux debian ( https://git01.codeplex.com/casablanca ) with procedure https://casablanca.codeplex.com/wikipage?title=Setup%20and%20Build%20on%20Linux&referringTitle=Documentation
after compilation i get a libcpprest.so with that (objdump) :
SONAME libcpprest.so.2.2
so you might want to copy libcpprest.so.2.2 to /usr/lib/libcpprest.so.2.2
or use ldconfig tool to do so.
looking into Release/build.release/Binaries you will find :
libcpprest.so -> libcpprest.so.2.2
libcpprest.so.2.2
then libcpprest.so is just a link, real library is libcpprest.so.2.2
The section you are referring to is tuned by the rpath switch:
g++ -Wl,-rpath,/path/to/lib ...