Linking shared library absolute vs. relative path - gcc

I've been trying to link a shared library into my program and I want its path to be relative to my RPATH.
However, when I ran ldd, I noticed that the absolute path of the shared library was linked. Any ideas why?
Edit:
/home/projects/my_files/winter_fresh.so
libgcc_s.so.1 => /home/tomo/anaconda3/lib/libgcc_s.so.1 (0x00007f0a3bf64000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0a3bd47000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0a3b97d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0a3e369000)
libstdc++.so.6 => /home/tomo/anaconda3/lib/libstdc++.so.6 (0x00007f0a3b643000)
The issue is the first file. I don't want the library for winter_fresh to be an absolute path, since I have an RPATH that contains it.

The issue is the first file. I don't want the library for winter_fresh to be an absolute path
This most usually happens when you link against your library like so:
gcc ... /home/projects/my_files/winter_fresh.so ...
and your library does not have SONAME (you didn't use -soname linker option when building it).
To fix this, either add SONAME to winter_fresh.so (a good practice in general), or link against it like so:
gcc ... -L /home/projects/my_files -l:winter_fresh.so
An even better approach might be to rename winter_fresh.so to libwinter_fresh.so, and then link against it like so:
gcc ... -L /home/projects/my_files -lwinter_fresh

My guess is, you compiled your program using winter_fresh.so as source file, not by linking against it.
If you encoded the path to shared library/executable as /home/projects/my_files/winter_fresh.so, you can put your shared library inside RPATH directory, like this:
$ mkdir some_dir
$ mkdir -p some_dir/home/projects/my_files
$ cp /home/projects/my_files/winter_fresh.so some_dir/home/projects/my_files
$ RPATH=$(pwd)/some_dir ./executable
The linker searches for library named /home/projects/my_files/winter_fresh.so under RPATH.
Now a simple test:
// main.c
int main() {
int external_function(void);
return external_function();
}
// exlib.c
#include <stdio.h>
int external_function(void) {
return printf("%s\n", __func__);
}
Now, let's create bad.out compiled with exlib.so shared library used as source:
$ gcc -shared -fPIC -o exlib.so exlib.c
$ gcc /tmp/exlib.so main.c -o bad.out
$ ldd bad.out
linux-vdso.so.1 (0x00007ffd921db000)
/tmp/exlib.so (0x00007fe4470f7000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fe446d3b000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fe4474fb000)
As you see the string /tmp/exlib.so points to the shared library. I can run the program, using RPATH to point the linker to exlib.so location. I need to create subtree /tmp/exlib.so inside RPATH, like this:
$ mkdir -p lib/tmp
$ mv exlib.so lib/tmp
$ RPATH=$(pwd)/lib ./bad.out
external_function
When running bad.out, linker searches for a file named /tmp/exlib.so inside RPATH.
Linux uses a convention for naming shared libraries. Now let's link against good.out:
$ gcc -shared -fPIC -o libexlib.so exlib.c
$ gcc -I /tmp -lexlib main.c -o good.out
$ ldd good.out
linux-vdso.so.1 (0x00007ffcb01bf000)
libexlib.so => not found
libc.so.6 => /usr/lib/libc.so.6 (0x00007fc1230ef000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fc1236ad000)
Now you see that good.out is linked against libexlib.so. gcc searched for alibrary named libexlib.so inside /tmp directory when linking. I can run good.out by specyfing LD_LIBRARY_PATH to the path libexlib.so resides:
$ LD_LIBRARY_PATH=/tmp ldd ./good.out
external_function

Related

Why explicite -L flag breaks linking on gcc

If this works as expected:
Lenovo#Lenovo-Komputer MINGW64 ~/source/hft (master)
$ gcc.exe main.c -o main.exe -lmsvcr110 && ldd ./main.exe # main.exe links to /c/WINDOWS/SYSTEM32
ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ff8d6130000)
KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ff8d3a30000)
KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7ff8d2030000)
msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7ff8d5e70000)
MSVCR110.dll => /c/WINDOWS/SYSTEM32/MSVCR110.dll (0x7ff8c3980000)
then why issuing this command in following manner ends up with this error?
Lenovo#Lenovo-Komputer MINGW64 ~/source/hft (master)
$ gcc.exe main.c -o main -lmsvcr110 -L /c/WINDOWS/SYSTEM32/ && ldd ./main.exe # so why explicit path makes linking error?
d000027.o:(.idata$5+0x0): multiple definition of `__imp___C_specific_handler'
d000024.o:(.idata$5+0x0): first defined here
d000057.o:(.idata$5+0x0): multiple definition of `__imp___iob_func'
d000031.o:(.idata$5+0x0): first defined here
d000057.o:(.idata$6+0x0): multiple definition of `__nm___iob_func'
d000031.o:(.idata$6+0x0): first defined here
d000058.o:(.idata$5+0x0): multiple definition of `__imp___setusermatherr'
d000034.o:(.idata$5+0x0): first defined here
d000058.o:(.idata$6+0x0): multiple definition of `__nm___setusermatherr'
d000034.o:(.idata$6+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

Linking to so library in gcc

I will start by saying that I am new to gcc and makefiles. I have a .so file on the desktop (~/Desktop) called lib.so. I want to link my program (called myProgram) to it. What I wrote in my makefile is:
g++ myProgram.o -L ~/Desktop -l lib -o myProgram
When I run make I get an error:
/usr/bin/ld: cannot find -llib
I also tried -l lib.so and got the same error.
What is the correct way to link?
Two solutions:
Rename the file to libsomething.so, then use -l something. The linker automatically wraps the name with lib prefix and .so suffix (or .a suffix for static libraries).
Use the option -l :lib.so. When you prefix the name with :, the linker uses the name as given.
These are explained in the ld man page.

Force solib dependency to have relative path of non-standard named shared library under a directory using gcc

I have an issue regarding the linking of a shared library with a non-standard naming convention under several directories. I need the generated executable to search for the shared library within the executables current location, but cannot find a command line parameter to force this behavior.
To demonstrate this behavior all that is required is a shared library that is under a directory.
gcc -shared mylib.c -o some/dir/mylib.so
gcc main.c -o main -Lsome/dir -l:mylib.so
The executable main gives the following ldd output:
ldd main
some/dir/mylib.so (0xf76e2000)
The output that I require is:
ldd main
mylib.so => some/dir/mylib.so (0xf7700000)
This output can be created if the library is named conventionally as libmylib.so rather than mylib.so like so:
mv some/dir/mylib.so some/dir/libmylib.so
gcc main.c -o main -Lsome/dir -lmylib
This also drops the path some/dir in the ldd listing as required.
I have investigated the use of rpath, and command line options for both the ld and gcc but I am unable to find a satisfactory solution. The strict requirements of a non-standard name and directory structure cannot be changed easily in this case.
My question is how can I force the dependency of the library to be relative to the current directory rather than absolute as in the second ldd through gcc command line options.
Thank you for your time, I hope I have explained the problem reasonably.
Jon.
Try to add soname in your shared library:
$ gcc -shared mylib.c -o some/dir/mylib.so -Wl,-soname=mylib.so
$ gcc main.c -o main -Lsome/dir -l:mylib.so
$ LD_LIBRARY_PATH=some/dir:$LD_LIBRARY_PATH ldd main
mylib.so => some/dir/mylib.so (0x00007fa7a4fd6000)
There's a magic variable you can pass to rpath to do this: $ORIGIN. See man ld.so for details.
I think in your case, the command should look like this (untested):
gcc main.c -o main -Lsome/dir -lmylib -Wl,-rpath,'$ORIGIN/some/path'
Note that you mustn't let the shell expand $ORIGIN as a shell variable.
BTW, this was the first Google hit for "rpath relative".

rpath=$ORIGIN not having desired effect?

I've got a binary "CeeloPartyServer" that needs to find libFoundation.so at runtime, on a FreeBSD machine. They're both in the same directory. I compile (on another platform, using a cross compiler) CeeloPartyServer using linker flag -rpath=$ORIGIN.
> readelf -d CeeloPartyServer |grep -i rpath
0x0000000f (RPATH) Library rpath: [$ORIGIN]
> ls
CeeloPartyServer Contents Foundation.framework libFoundation.so
> ./CeeloPartyServer
/libexec/ld-elf.so.1: Shared object "libFoundation.so" not found, required by "CeeloPartyServer"
Why isn't it finding the library when I try to run it?
My exact linker line is: -lm -lmysql -rpath=$ORIGIN.
I am pretty sure I don't have to escape $ or anything like that since my readelf analysis does in fact show that library rpath is set to $ORIGIN. What am I missing?
I'm assuming you are using gcc and binutils.
If you do
readelf -d CeeloPartyServer | grep ORIGIN
You should get back the RPATH line you found above, but you should also see some entries about flags. The following is from a library that I built.
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../lib]
0x000000000000001e (FLAGS) ORIGIN
0x000000006ffffffb (FLAGS_1) Flags: ORIGIN
If you aren't seeing some sort of FLAGS entries, you probably haven't told the linker to mark the object as requiring origin processing. With binutils ld, you do this by passing the -z origin flag.
I'm guessing you are using gcc to drive the link though, so in that case you will need to pass flag through the compiler by adding -Wl,-z,origin to your gcc link line.
Depending on how many layers this flag passes through before the linker sees it, you may need to use $$ORIGIN or even \$$ORIGIN. You will know that you have it right when readelf shows an RPATH header that looks like $ORIGIN/../lib or similar. The extra $ and the backslash are just to prevent the $ from being processed by other tools in the chain.
\$\ORIGIN if you are using chrpath and \$\$ORIGIN if you are providing directly in LDFLAGS
using ldd CeeloPartyServer to check the dependency .so is starting with ./ or not. (e.g. libFoundation.so and ./libFoundation.so)
For common situation it should be libFoundation.so and without the prefix ./
if ./ prefix is necessary for some uncommon case, make sure the CWD is the same folder with libFoundation.so, and the $ORIGIN would be invalid.
=======
For example:
g++ --shared -Wl,--rpath="\$ORIGIN" ./libFoundation.so -o lib2.so
would got a library lib2.so with ./libFoundation.so
g++ --shared -Wl,--rpath="\$ORIGIN" libFoundation.so -o lib2.so
would got libFoundation.so instead.

ld: library not found for -lcrt0.o on OSX 10.6 with gcc/clang -static flag

When I try to build the following program:
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
On OS X 10.6.4, with the following flags:
gcc -static -o blah blah.c
It returns this:
ld: library not found for -lcrt0.o
collect2: ld returned 1 exit status
Has anyone else encountered this, or is it something that noone else has been affected with yet? Any fixes?
Thanks
This won’t work. From the man page for gcc:
This option will not work on Mac OS X unless all libraries (including libgcc.a) have also been compiled with -static. Since neither a static version of libSystem.dylib nor crt0.o are provided, this option is not useful to most people.
Per Nate's answer, a completely static application is apparently not possible - see also man ld:
-static Produces a mach-o file that does not use the dyld. Only used building the kernel.
The problem in linking with static libraries is that, if both a static and a dynamic version of a library are found in the same directory, the dynamic version will be taken in preference. Three ways of avoiding this are:
Do not attempt to find them via the -L and -l options; instead, specify the full paths, to the libraries you want to use, on the compiler or linker command line.
$ g++ -Wall -Werror -o hi /usr/local/lib/libboost_unit_test_framework.a hi.cpp
Create a separate directory, containing symbolic links to the static libraries, use the -L option to have this directory searched first, and use the -l option to specify the libraries you want to use.
$ g++ -Wall -Werror -L ./staticBoostLib -l boost_unit_test_framework -o hi hi.cpp
Instead of creating a link of the same name in a different directory, create a link of a different name in the same directory, and specify that name in a -l argument.
$ g++ -Wall -Werror -l boost_unit_test_framework_static -o hi hi.cpp
You may also try LLVM LLD linker - I did prebuilt version for my two major OSes - https://github.com/VerKnowSys/Sofin-llds
This one allows me to link for exmple: "Qemu" properly - which is impossible with ld preinstalled by Apple.
And last one is - to build GCC yourself with libstdc++ (don't).

Resources