I am working on a CentOS machine. I have a file (test.c) that I'm compiling into a shared library.
test.c:
#include <stdio.h>
#include <stdlib.h>
#include <quadmath.h>
int my_func(void){
__float128 r;
r = strtoflt128 ("1.2345678", NULL);
int * b = malloc(sizeof(int) * 5);
double a = 10*M_PI_2q;
printf("Hello world %f\n",a);
return 0;
}
To compile it :
$ gcc -c -fPIC test.c -o test.o
$ gcc -shared -Wl,--verbose -Wl,-soname,poo.so -Wl,-rpath,/opt/gcc/5.5.0/lib/ -o poo.so test.o -lquadmath
$ echo $LD_LIBRARY_PATH ### This shouldn't matter?
/opt/gcc/5.5.0/lib
From the verbose output from ld, it looks like it /opt/gcc/5.5.0/lib64/libquadmath.so.0 is found (which is what I want). I.e.
.
.
.
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.5.0/libquadmath.so failed
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.5.0/libquadmath.a failed
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/libquadmath.so failed
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/libquadmath.a failed
attempt to open /opt/gcc/5.5.0/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.5.0/../../../../lib64/libquadmath.so succeeded
-lquadmath (/opt/gcc/5.5.0/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.5.0/../../../../lib64/libquadmath.so)
.
.
.
However, when I look with ldd poo.so, it does not have the correct library. I.e.
$ ldd poo.so
linux-vdso.so.1 => (0x00007fffc0e8e000)
libquadmath.so.0 => /act/gcc-4.7.2/lib64/libquadmath.so.0 (0x00002aea8fd39000)
libc.so.6 => /lib64/libc.so.6 (0x00002aea8ff6f000)
libm.so.6 => /lib64/libm.so.6 (0x00002aea90303000)
/lib64/ld-linux-x86-64.so.2 (0x00002aea8f8f2000)
I am using gcc version 5.5.0 and would like poo.so to link to /opt/gcc/5.5.0/lib/libquadmath.so.0 instead of the 4.7.2 version.
I think this is related to the existence of files in /etc/ld.so.conf specifying the location of the older libraries. I.e.
$ cat /etc/ld.so.conf.d/gcc-4.7.2.conf
/act/gcc-4.7.2/lib64
/act/gcc-4.7.2/lib
The man page of ld (as I inquired here) is less than useful.
QUESTION : I specify -rpath when linking and building the shared library, yet I don't understand why it is finding the older gcc-4.7.2 version of the quadmath library. Why does the linker seem to prioritize the paths in /etc/ld.so.conf and ignore the -rpath option? How can I specify the library location at compile time and how do I fix this?
To understand the solution, first we must understand the incorrect thinking.
I did not realize that there two utilities doing linking. There is ld (which is used at compile time) and ld.so (which is used at run time). The man page of ld.so describes how libraries are found at run time. To summarize it searches :
a) Directories specified in DT_RPATH
b) Directories specified in LD_LIBRARY_PATH
c) Directories in DT_RUNPATH dynamic section of binary (if present)
d) Cache file /etc/ld.so.cache
e) The default path /lib and then /usr/lib
The man page of ld primarily confused me. It says under the -rpath option:
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects
I thought that passing -rpath when building a shared library would
guarantee that it would find the library without needing to set
LD_LIBRARY_PATH. Wrong. This feature only seems to be useful
when building an executable, not a shared library. There is an -rpath-link option, but I couldn't figure out how to make it work.
You can see this by doing the following:
$ cat test2.c
#include <stdio.h>
#include <stdlib.h>
#include <quadmath.h>
int main(void){
__float128 r;
r = strtoflt128 ("1.2345678", NULL);
int * b = malloc(sizeof(int) * 5);
double a = 10*M_PI_2q;
printf("Hello world %f\n",a);
return 0;
}
$ export LD_LIBRARY_PATH=
$ which gcc
/opt/gcc/5.5.0/bin/gcc
$ gcc -Wl,-rpath,/opt/gcc/5.5.0/lib64 test2.c -lquadmath
$ ldd a.out
linux-vdso.so.1 => (0x00007fffff34f000)
libquadmath.so.0 => /opt/gcc/5.5.0/lib64/libquadmath.so.0 (0x00002b9c35e07000)
libc.so.6 => /lib64/libc.so.6 (0x00002b9c36069000)
libm.so.6 => /lib64/libm.so.6 (0x00002b9c363fd000)
/lib64/ld-linux-x86-64.so.2 (0x00002b9c35be5000)
$ readelf -a a.out | grep -i rpath
0x000000000000000f (RPATH) Library rpath: [/opt/gcc/5.5.0/lib64]
The way that the linker found the correct library was by utilizing the path to /opt/gcc/5.5.0/bin/gcc and looking at relative paths with respect to it. I checked this by setting export LD_LIBRARY_PATH= and excluding the rpath argument, i.e. gcc -shared -Wl,--verbose -Wl,-soname,poo.so -o poo.so test.o -lquadmath. Even then, it was able to link to the correct libquadmath.so.0 library.
The reason that ldd poo.so could not find the correct library was because it wanted the 64-bit version of the libquadmath.so.0 library IS NOT /opt/gcc/5.5.0/lib/libquadmath.so.0. That is the 32-bit version of the library. This is obvious once you inspect both versions of the library and see that the they are ELF64 and ELF32 respectively (e.g. readelf -a /opt/gcc/5.5.0/lib64/libquadmath.so.0 | grep Class).
Since I never specify the path to the correct library that it is looking for, ld.so by default looked at /etc/ld.conf.cache (which builds on `/etc/ld.conf.d/') to decide which directories to look in. This is why it found the 4.7.2 version of quadmath.
To get the correct library at runtime, I need to set export
LD_LIBRARY_PATH=/opt/gcc/5.5.0/lib64.
Summary, it was finding the correct library at compile time using ld (b/c it looked at the relative paths of gcc) but could not find the correct library at run time (b/c LD_LIBRARY_PATH was incorrectly set). The solution is :
export LD_LIBRARY_PATH=/opt/gcc/5.5.0/lib64. -rpath is not a valid option when building a shared library.
The path specified by --rpath option will be hard coded into binary you created. At running time, ld will search dependent libraries from those paths preferentially. This is determined by ld.so.
But when you compile program, The linker will search dependent libraries from LD_LIBRARY_PATH and those folder you specified by -L option. At compiling time, the path specified by --rpath do not take effect. This is determined by ld, the GNU linker.
Related
Thanks in advance.
my development environment:
$ cat /proc/version
Linux version 5.4.0-66-generic (buildd#lgw01-amd64-016) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #74~18.04.2-Ubuntu SMP Fri Feb 5 11:17:31 UTC 2021
$ ld --version
GNU ld (GNU Binutils for Ubuntu) 2.30
Copyright (C) 2018 Free Software Foundation, Inc.
$ getconf GNU_LIBC_VERSION
glibc 2.27
$ #my glibc source version is 2.32.9000-development
$ cat ./version.h
/* This file just defines the current version number of libc. */
#define RELEASE "development"
#define VERSION "2.32.9000"
For some reasons, I need to modify and test glibc. I follow the steps of this website(https://sourceware.org/glibc/wiki/Testing/Builds#Compile_against_glibc_in_an_installed_location) to modify glibc and write test programs.
compile glibc.(confgure and make)
install glibc.(make install to a directory)
...other steps in the website above.
I successfully modified some pthread functions and passed the test (the test program I wrote can compiled against the install glibc and ran successfully). ldd the program.
$ ldd ./exec/1-1.out
linux-vdso.so.1 (0x00007ffcbf367000)
libpthread.so.0 => /home/cjl-target/gnu/install/lib64/libpthread.so.0 (0x00007fcadcea9000)
libc.so.6 => /home/cjl-target/gnu/install/lib64/libc.so.6 (0x00007fcadcaed000)
/home/cjl-target/gnu/install/lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fcadd2ca000)
As shown above, the shared libraries that the program depends on all point to the glibc installation path.
But when I compiled message-queue's test program(test mq_unlink) and ran it, failed as bellow:
./exec/1-1.out: symbol lookup error: /lib/x86_64-linux-gnu/libpthread.so.0: undefined symbol: __libc_vfork, version GLIBC_PRIVATE
check the library that is depended by the program:
$ ldd ./exec/1-1.out
linux-vdso.so.1 (0x00007ffce3f72000)
librt.so.1 => /home/cjl-target/gnu/install/lib64/librt.so.1 (0x00007f0a389a2000)
libc.so.6 => /home/cjl-target/gnu/install/lib64/libc.so.6 (0x00007f0a385e6000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0a383c7000)
/home/cjl-target/gnu/install/lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f0a38dac000)
As shown above, the shared libraries libpthread.so.0 points to the system library. Why?
my compile script is(from the website above):
# dobuild.sh
SYSROOT=/home/xxx/xxx/xxx #the glibc's installation path
(set -x; \
gcc \
-L${SYSROOT}/usr/lib64 \
-I${SYSROOT}/usr/include \
--sysroot=${SYSROOT} \
-Wl,-rpath=${SYSROOT}/lib64 \
-Wl,--dynamic-linker=${SYSROOT}/lib64/ld-linux-x86-64.so.2 \
-Wall $*
)
when I compile the pthread's test program:./dobuild 1-1.c -pthread -Wall
when I compile the mq's test program:./dobuild 1-1.c -lrt -Wall
In addition, it is confusing that when invoke the pthread_create in the mq_unlink's test program, compiling it ./dobuild 1-1.c -lrt -pthread, the ldd result shows that all dependent libraries point to the installed glibc.
I've tried multiple variations of this, but none of them seem to work. Any ideas?
First, you should stop using ldd -- in the presence of multiple GLIBCs on a host, ldd is more likely to mislead than to illuminate.
If you want to see which libraries are really loaded, do this instead:
LD_TRACE_LOADED_OBJECTS=1 ./exec/1-1.out
Second, you should almost never use $* in shell scripts. Use "$#" instead (note: quotes are important). See this answer.
Third, the behavior you are observing is easily explained. To understand it, you need to know the difference between DT_RPATH and DT_RUNPATH, described here.
You can verify that your binaries are currently using RUNPATH, like so:
readelf -d 1-1.out | grep 'R.*PATH'
And you can verify that everything starts working as you expect by adding -Wl,--disable-new-dtags to the link command (which would cause the binary to use RPATH instead).
To summarize:
RUNPATH affects the search for the binary itself, but not for any libraries the binary depends on.
RPATH affects the search path for the binary and all libraries it depends on.
with RUNPATH, expected libpthread.so.0 is found only when the binary depends on it directly, but not when the dependency on libpthread is indirect (via librt).
with RPATH, expected libpthread.so.0 is found regardless of whether the dependency is direct or indirect.
Update:
If I want to use DT_RUNPATH, how to set the library runpath for librt?
You would need to link librt.so with -rpath=${SYSROOT}/lib64.
You could edit the rt/Makefile, or build with:
make LDFLAGS-rt.so='-Wl,--enable-new-dtags,-z,nodelete,-rpath=${SYSROOT}/lib64'
You would need to do the same for any other library that may bring transitive dependency on other parts of GLIBC. I don't know of a general way to do this, but setitng LDFLAGS-lib.so='-Wl,-rpath=${SYSROOT}/lib64' and rebuilding everything might do the trick.
I am trying to compile a program to have all libraries statically inside the final binary, but I still want glibc to be dynamically linked. If I use "-static" it compiles ALL libraries statically, including glibc. Basically I need a -static parameter together with something like -exclude=glibc
Would be awesome with both an example when using "make" as well as an example with pure "gcc". Running "ldd" on the final binary should show only glibc dynamically linked.
You can link a subset of libraries statically using -Bstatic and -Bdynamic. On the GCC command line, this looks like this (for linking statically against PCRE, just as an example):
-Wl,-Bstatic -lpcre -Wl,-Bdynamic
Note that -lanl, -ldl, -lm, -lmvec, -lnsl, -lpthread, -lresolv, -lrt, -lutil are all part of glibc and must therefore come after the -Wl,-Bdynamic (so that they are linked dynamically). For -lcrypt, this depends on the distribution.
What you ask can be done on some systems, approximately, but not with GCC's -static option. That option has global effect on linking:
On systems that support dynamic linking, this overrides -pie and prevents linking with the shared libraries. On other systems, this option has no effect.
(GCC 9.2 manual)
To have the wanted level of control over linking, you need to pass flags through to the linker. You can do that with GCC's -Wl option. If you are using GCC then you are presumably also using the GNU linker, and on build targets that support both static and dynamic linking, it has a variety of mechanisms for mixing them. In particular, the GNU linker's -Bstatic flag and its counterpart -Bdynamic flag each take effect only for libraries named after them on the command line, up to the next such flag. That is, they allow you to switch back and forth between designating libraries for static linking and for dynamic linking.
Example:
This C program requires the math library to be linked, which is not automatic with GCC:
link_test.c:
#include <stdio.h>
#include <math.h>
int main(void) {
printf("The square root of 2 is approximately %f\n", sqrt(2.0));
}
This gcc command will cause the-lm to be linked statically, but libc to be linked dynamically:
gcc -o link_test link_test.c -Wl,-Bstatic -lm -Wl,-Bdynamic
Any number of addional -l options, library names, and object file names could be put between the -Wl,-Bstatic and -Wl,-Bdynamic options along with -lm; all such objects will be linked statically. Although libc is not explicitly linked (GCC does not require that), leaving the link type toggled to "dynamic" at the end of the explicit argument list does, for me, cause libc to be linked dynamically:
$ ldd link_test
linux-vdso.so.1 => (0x00007ffe185af000)
libc.so.6 => /lib64/libc.so.6 (0x00002b775f059000)
/lib64/ld-linux-x86-64.so.2 (0x00002b775ee35000)
(Observe that libm does not appear in the dynamic library listing, unlike when -Wl,-Bstatic is not used, but libc does.)
Note that your objective that "Running 'ldd' on the final binary should show only glibc dynamically linked" is not necessarily viable, as the above ldd output demonstrates. If your executable is dynamically linked at all, then in addition to any dynamic libraries it will have the dynamic loader linked in, and possibly also platform-specific pseudo-libraries such as linux-vdso.so.1.
You ask for a makefile example, but that's like asking just "write me a program". Nothing about this is make-specific, and there are innumerable ways to incorporate the above approach into a makefile. But since you asked, this is one of the simplest possible variations:
Makefile
link_test: link_test.c
gcc -o $# $< -Wl,-Bstatic -lm -Wl,-Bdynamic
Is there a way to get compilers to prefer libraries from LIBRARY_PATH instead of system paths. I am particularly looking for Clang. I partially solved the problem for GCC while writing this question, but it's also not quite clear.
Background
LIBRARY_PATH is a convenient environment variable to allow transparently linking libraries in non-standard directories, e.g. user installations, and in my case environment modules that provide different versions of a library.
The idea is to do a module load libfoo/version and the compiler will transparently use the right libfoo.so.
For a shared library, one also needs to set LD_LIBRARY_PATH for ld.so to find the right library. If there are multiple libfoo.so in both LD_LIBRARY_PATH and /usr/lib, ld.so specifies that LD_LIBRARY_PATH is searched before default paths.
Problem
I have encountered issues when the library defines a soname - which is different between the two libfoo.so versions (which are symlinks to libfoo.so.1 and libfoo.so.2 respectively) in /usr/lib and LIBRARY_PATH. Then ld will link against the soname in /usr/lib and LD_LIBRARY_PATH can no longer prioritize the intended library.
I first encountered this with boost, but here's a small example:
echo "void foo() {}" > foo.c
# create an old libfoo version in /usr/lib
sudo gcc foo.c -fpic -shared -o /usr/lib/libfoo.so.1 -Wl,-soname,libfoo.so.1
sudo ln -s libfoo.so.1 /usr/lib/libfoo.so
# create the new libfoo that we want to transparently override
mkdir -p /tmp/XXX/lib
gcc foo.c -fpic -shared -o /tmp/XXX/lib/libfoo.so.2 -Wl,-soname,libfoo.so.2
ln -s libfoo.so.2 /tmp/XXX/lib/libfoo.so
export LIBRARY_PATH=/tmp/XXX/lib
export LD_LIBRARY_PATH=/tmp/XXX/lib
echo "void foo(); int main() { foo(); }" > main.c
gcc main.c -lfoo
ldd a.out| grep foo
# under some conditions this shows libfoo.so.1 instead of .2
libfoo.so.1 => /usr/lib/libfoo.so.1
GCC
I initially encountered this issue with a custom installation of GCC while it was working as expected for the system installation.
gcc --print-search-dirs reveals a pattern:
/tmp/XXX/lib/x86_64-pc-linux-gnu/7.2.0/
/tmp/XXX/lib/x86_64-linux-gnu/
/tmp/XXX/lib/../lib64/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../x86_64-pc-linux-gnu/lib/x86_64-pc-linux-gnu/7.2.0/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../x86_64-pc-linux-gnu/lib/x86_64-linux-gnu/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../x86_64-pc-linux-gnu/lib/../lib64/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../x86_64-pc-linux-gnu/7.2.0/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../x86_64-linux-gnu/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib64/
/lib/x86_64-pc-linux-gnu/7.2.0/
/lib/x86_64-linux-gnu/
/lib/../lib64/
/usr/lib/x86_64-pc-linux-gnu/7.2.0/
/usr/lib/x86_64-linux-gnu/
/usr/lib/../lib64/
/tmp/XXX/lib/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../x86_64-pc-linux-gnu/lib/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../
/lib/
/usr/lib/
In addition to the normal search priority - where LIBRARY_PATH comes before system paths, GCC prioritizes a few "prefixes", including ../lib64. This can be worked around by creating another symlink:
ln -s lib /tmp/XXX/lib64
I thought this was related to the --libdir parameter during configure, which I omitted and is /usr/lib in the system installation, but even if i specify --libdir=$PREFIX/lib --libexecdir=$PREFIX/lib, it prefers ../lib64.
How to compile or control gcc at runtime so that it at least uses the ../lib instead of ../lib64 postfix?
Clang
Clang is even more uncooperative. It does not include LIBRARY_PATH in the output for --print-search-dirs and does not even include a -L/tmp/XXX/lib to it's call to ld if the libfoo.so can be found already in /usr/lib.
How can I get Clang to prioritize my library path transparently?
Notes
Examples are from Archlinux, but I also tested under Ubuntu 16.04 which behaves similarly.
Related questions for GCC: Why does g++ look in LIBRARY_PATH/../lib64 and where is this documented? and g++ searches /lib/../lib/, then /lib/.
Overriding the search order with -L works, but is not transparent.
gcc --print-search-dirs lists more directories than gcc -v. The latter filters out non-exiting paths.
I found out the reason why a custom installation of GCC is different. Debian distribution patches the GCC makefiles, that's how it gets the right priority of LIBRARY_PATH. Before building GCC, find gcc/config/i386/t-linux64 and there change all MULTILIB_OSDIRNAMES to these lines:
MULTILIB_OSDIRNAMES = m64=../lib$(call if_multiarch,:x86_64-linux-gnu)
MULTILIB_OSDIRNAMES+= m32=../lib32$(call if_multiarch,:i386-linux-gnu)
MULTILIB_OSDIRNAMES+= mx32=../libx32$(call if_multiarch,:x86_64-linux-gnux32)
Also add --libexecdir=/your/custom/path/lib --libdir=/your/custom/path/lib to configure.
My system is an older NAS running 2.6.32. I have found that when using -static for any subsequent library, it will also try to statically link any other library that I might need.
When I add the -Wl,-Bdynamic flag first and then explicitly name those libraries using -lc, such as "-Wl,-Bdynamic -lc -lstdc++" then it works. So what happens is that libc and others fail to be statically linked.
The static libc on the system is called /opt/lib/libc_nonshared.a.
The contents of /opt/lib/libc.so is this:
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( /lib/libc.so.6 /opt/lib/libc_nonshared.a )
The gcc version is 4.2.3. The current build command I am facing adds -dynamic at the end but this doesn't help much. When I add some static library directly using its .a name, and not using a -l flag, then there is no issue.
The problem seems to be that the dynamic library of libc came with the NAS, but the static version sits in /opt/lib.
I run:
gcc hamming.c -static -L. -L/opt/lib -l:matrix.a -o hamming
I get:
/opt/lib/gcc/arm-none-linux-gnueabi/4.2.3/../../../../arm-none-linux-gnueabi/bin/ld: cannot find -lc
collect2: ld returned 1 exit status
make: *** [hamming] Error 1
when I try to use static libc as is. Were I to perform a 'hack' to link libc_nonshared.a to libc.a, it suddenly does find it. But complains:
hamming.c:54: undefined reference to `malloc'
hamming.c:54: undefined reference to `memset'
And a zillion other errors of course. As mentioned above, /opt/libc.so contains the reference to both files (dynamic and static).
For libstdc++ only a .la file exists.
The -static linker flag does not take any argument. It is a boolean
flag that simply directs the linker to link no shared libraries, as
documented
-static
Do not link against shared libraries...
There is no need to explicitly direct the linker to link shared (dynamic)
libraries when it has a choice because that is the default bevaiour. If
you simply link, e.g.
gcc -o prog ... -lfoo ...
then the linker will link the first of libfoo.so (shared) or libfoo.a
(static) that it finds in any of the specified (-Ldir) or default
search directories, searched in commandline sequence. If it finds both
libfoo.so and libfoo.a in the same directory then it will choose
libfoo.so. Thus shared and static libraries may be freely intermixed
without any special options.
Specify -static only if you wish to link only static libraries.
If you wish to insist on linking a particular libfoo.a even when
libfoo.so is in the same directory and would be chosen by default,
use the explicit form of the -l option: -l:libfoo.a
Later
gcc hamming.c -static -L. -L/opt/lib -l:matrix.a -o hamming
This command is failing with:
ld: cannot find -lc
because the linker (ld) cannot find a static library libc.a in
any of the specified linker search directories (-L. -L/opt/lib) or
the default linker search directories. If you wish instead to link
/opt/lib/libc_nonshared.a then your command should be:
>gcc hamming.c -static -L. -L/opt/lib -l:matrix.a -lc_nonshared -o hamming
However, you have not explained why you want to link this program statically
(-static) in the first place, which is not the usual way and will require you to have installed
static versions of all libraries required for the linkage - both those
you explicitly link and the default libraries that gcc will add for C language
linkage (Standard C library, GCC runtime library).
Supposing you have a static library called (oddly) matrix.a (rather
than normally, libmatrix.a) that is located in /some/dir/, then the
normal way to compile and link your program would be:
gcc hamming.c -L/some/dir -l:matrix.a -o hamming
I suggest you start with that and deviate only as problems compel
you to.
The discovery of an /opt/lib/libc.so containing:
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( /lib/libc.so.6 /opt/lib/libc_nonshared.a )
is misleading you. This is not your shared libc. A shared library
is a binary. This is a linker script, and it says that your shared libc
is in fact /lib/libc.so.6. The linker will almost certainly find and use it by default.
How can I force the gcc linker to link against a given version (soname) of a shared library on the system?
I need this to enforce that the version of openssl that is #include'ed matches the version that is linked, on any system, even if multiple versions of openssl are installed. To find the ABI version, my configure script first compiles and runs a program that extracts the SONAME from the headers:
#include <openssl/opensslv.h>
#include <stdio.h>
int main () {
printf(SHLIB_VERSION_NUMBER);
return 0;
}
The SHLIB_VERSION_NUMBER contains the so version string, e.g. 0.9.8 or 1.0.2k or 1.1.0. But how do I tell gcc to link against this version of libssl or libcrypto rather than just any -lssl?
I tried "in situ" linking, so that instead of linking with gcc main.c -lcrypto we use:
gcc main.c libcrypto.so.1.1.0
However it seems the linker libcrypto.so.1.1.0 cannot be found:
gcc: error: libcrypto.so.1.1.0: No such file or directory
I guess the system only searches in the standard locations when using the -l flag. Is there a better way to make my software link against libcrypto.so.1.1.0?
To select the correct version of the openssl shared libraries use:
gcc main.c -l:libssl.so.1.0.0 -l:libcrypto.so.1.0.0
The key to answering this question is "how do I control ld so that is links the correct version of a shared library?".
The correct way to pass a linker flag (a command line parameter to ld) using the gnu compilers (gcc, g++, gdc, etc...) is to use the normal ld parameter prefixed with "-l". For example -lssl or -L/usr/local/lib.
Edit: As per How to specify the library version to use at link time? you can read the manual for ld with:man ld.