How do you link to a specific version of a shared library in GCC
I’m compiling some code which uses libcurl on a Debian Linux system. My dev machine is running Debian 5 but I want the binary to be usable on older Debian 4 systems too. I find that if I specify -lcurl it will link to libcurl.so.4 but Debian 4 systems only have libcurl.so.3 Is there some way I can tell GCC to link to either libcurl.so.3 (which exists in both Debian 4 and 5) or just libcurl.so so it will use whatever version is available ?
On the older Debian, isn’t libcurl.so a symlink to libcurl.so.3 ? I mean, it looks strange that -lcurl does not the right thing by default.
kastauyra: the versions are not, or at least cannot be assumed to be, binary compatible. So when you link it records the major version linked against in the binary: if you compile on the newer system it will require version 4 and not work on the old system. (Actually what it records is the soname, which is a string stored in the library file which conventionally but not necessarily is something «libcurl.so.3»)
4 Answers 4
Instead of using -lcurl use -l:libcurl.so.3 And of course also use -L _installed_path_
This doesn’t work for me even with the rpath. ldd shows it linking with one thing. The linked output shows the correct filename. But strace confirms it is loading file.2 instead of file.2.3 and it isn’t a symlink.
it does not really work for me for some reason, even if I replace symlink with actual file and delete all the other libraries its still linking against specific version, which it probably gets from the SONAME
You can pass the specific version shared library file using the syntax -l:libfoo.so.1 that specifies the filename instead of the syntax -lfoo that specifies the library name following the convention libfoo.so on the linker command line, and it ought to do what you want as can be seen at the linker documentation section for the option —library=namespec .
If namespec is of the form :filename, ld will search the library path for a file called filename
In order to provide more details on how to link to a specific version through an example, consider a system that contains two versions of the same library, namely libfoo.so.1.0 and libfoo.so.2.0 installed in one of the library directories, in this case /lib .
$ ls -l /lib/libfoo* lrwxrwxrwx root root /lib/libfoo.so -> /lib/libfoo.so.2 lrwxrwxrwx root root /lib/libfoo.so.1 -> /lib/libfoo.so.1.1 -rwxr-xr-x root root /lib/libfoo.so.1.0 -rwxr-xr-x root root /lib/libfoo.so.1.1 lrwxrwxrwx root root /lib/libfoo.so.2 -> /lib/libfoo.so.2.2 -rwxr-xr-x root root /lib/libfoo.so.2.0 -rwxr-xr-x root root /lib/libfoo.so.2.1 -rwxr-xr-x root root /lib/libfoo.so.2.2 # ldconfig -p | grep libfoo libfoo.so.2 (libc6,x86-64) => /lib/libfoo.so.2 libfoo.so.1 (libc6,x86-64) => /lib/libfoo.so.1 libfoo.so (libc6,x86-64) => /lib/libfoo.so
A program compiled with the option -lfoo will make the linker look for a file that relies on the naming convention and thus resolve to /lib/libfoo.so (for a shared library object) or /lib/libfoo.a (for a static library object).
A special file name convention is used for libraries: A library known as foo is expected to exist as the file libfoo.so or libfoo.a.
In contrast to that, a program compiled with the option -l:libfoo.so.1 will be linked against /lib/libfoo.so.1 , that is a itself currently a symbolic link to libfoo.so.1.1 as can be seen from the listing above, a minor update from 1.0.
And finally, a program compiled with the option -l:libfoo.so.2 will be linked against /lib/libfoo.so.2 , that is itself currently a symbolic link to libfoo.so.2.2 as can be seen from the listing above, a minor update from 2.0 and 2.1.
Should you install a newer version of such library, as long as it is a minor update, there should be no need to recompile programs linked to it, since compatible versions should have the same soname and the symbolic links should be updated accordingly.
The actual library foo version X.Y exists as the file libfoo.so.x.y. Inside the library file, a soname is recorded with the value libfoo.so.x to signal the compatibility.
$ ls -l /lib/libfoo.so.2* lrwxrwxrwx root root /lib/libfoo.so.2 -> /lib/libfoo.so.2.3 [. ] -rwxr-xr-x root root /lib/libfoo.so.2.3
How to do versioning of shared library?
Windows provides the resource file for version information for an application and DLL. The resource file includes information like version, copyright and manufacturer. We have a shared library and would like to add version information. How can we do it on Linux with a shared library?
3 Answers 3
The short version is that you do this via the soname of the library. Read chapter 3 at http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html as well as chapter 3.3 ABI Versioning at http://www.akkadia.org/drepper/dsohowto.pdf
Thanks for your answer, I was redirected from here but I still don’t understand how one program can understand which library version to use. I want that one program use one version and another the new version.
One comment on the Program-Library-HOWTO: if you are writting receipt for install in makefile, you should do nothing other than generating & copying files into destination dir. so do not call ldconfig in receipt, just create symbolic link file with soname to realname (for your bin-package) and create linkname to soname (for your dev-package), and installer can call ldconfig by themselves after «make install» if they install the library into non-standard location. because «make install» may be invoked for cross-compiling
The best way to handle this is using libtool, which does the versioning for you.
Essentially, version information is not (or not primarily, don’t know from my head) encoded in the library itself, but rather in its filename. Version numbers are normally given in three-dot format, with the major number increasing for each break in downward ABI compatibility, the middle for breaks in upward ABI compatibility, and the minor for patches that did not change the ABI.
Like qdot noted, symlinks in the lib directory provide the essential versioning. There is a symlink without a version number (libfoo.so) for the currently installed development headers, a symlink with a major number for each installed major version (libfoo.so.1) and a real file with the full version number. Normally, programs are linked to use libfoo.so.1 at runtime so that multiple major versions may coexist.
Viewing Linux Library / Executable version info
The version info in not explicitly stored in an ELF file. What you have in there is the name of the library, the soname , which includes the major version. The full version is usually stored as a part of the library file name.
If you have library, say libtest.so , then you usually have:
- libtest.so.1.0.1 — The library file itself, containing the full version
- libtest.so.1 — Symlink to libtest.so.1.0.1 , having the same name as soname
- libtest.so — Symlink to libtest.so.1 used for linking.
In the library file libtest.so.1.0.1 , there will be an entry called SONAME in dynamic section, that will say this library is called libtest.so.1 . When you link a program against this library, the linked program will store the soname of the library under NEEDED entry in the dynamic section.
If you want to verify, what exactly is in which ELF file, you can try to run:
where elffile can be either an library of an executable.
If you simply want to get the library version, you can play with:
readelf -d /path/to/library.so |grep SONAME
AFAIK, there’s no such info (at least not by default) in executable files.
Or you can rely on the program itself or your packaging system, as Rahul Patil wrote.
nice info, it’s new to me never used readelf, if you don’t mind , may i ask you where & why use readelf
Readelf (and similar tools) is useful, when you want to look inside an elf file :). I use it mostly when programming to look up symbols in libraries (when something doesn’t work), or when there’s some problem with a library. (man readelf)
You can use ldconfig -v | grep libraryname , also command has option command -V or binaryfile —version
test@ubuntukrb12:~# ls --version ls (GNU coreutils) 8.13 Copyright (C) 2011 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
also you can use yum or aptitude based on distro you are using eg.
in RHEL5/CENTOS5/Fedora you can use yum info packagename or if it installed then use rpm —version packagename
[root@ldap1 ~]# yum info bind97 Loaded plugins: downloadonly, fastestmirror, security Loading mirror speeds from cached hostfile * base: mirrors.sin3.sg.voxel.net * epel: mirror.imt-systems.com * extras: mirrors.sin3.sg.voxel.net * updates: mirrors.sin3.sg.voxel.net Installed Packages Name : bind97 Arch : i386 Epoch : 32 Version : 9.7.0 Release : 10.P2.el5_8.4 Size : 6.3 M Repo : installed Summary : The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) server URL : http://www.isc.org/products/BIND/ License : ISC Description: BIND (Berkeley Internet Name Domain) is an implementation of the DNS : (Domain Name System) protocols. BIND includes a DNS server (named), : which resolves host names to IP addresses; a resolver library : (routines for applications to use when interfacing with DNS); and : tools for verifying that the DNS server is operating properly.
In Ubuntu You can use aptitude show pkgname or dpkg —version pkgname
root@ubuntukrb12:~# aptitude show bind9utils Package: bind9utils State: installed Automatically installed: yes Version: 1:9.8.1.dfsg.P1-4ubuntu0.4 Priority: optional Section: net Maintainer: Ubuntu Developers Architecture: amd64 Uncompressed Size: 306 k Depends: libbind9-80, libc6 (>= 2.14), libdns81, libisc83, libisccc80, libisccfg82 Conflicts: bind9utils Replaces: bind9 (