Making executable which uses any available version of shared library is, of course, possible.
The problem was that you linked your executable to version-specific soname (libsomething.so.1
and libsomething.so.2
). You should have done it with unversioned soname libsomething.so
instead.
In order to achieve this, on the build machine you should compile and install library with soname (ELF SONAME
) equal to libsomething.so
(without version) so that linker can choose this soname while executable is built.
According to the Shared Libraries HOWTO, you can pass required unversioned soname while building the library:
gcc -shared -Wl,-soname,libsomething.so -o libsomething.so.X objectsomething.o
Then, as soon as you install the library and run ldconfig
, you have:
- symlink
/lib/libsomething.so
pointing to /lib/libsomething.so.1
on machine A;
- symlink
/lib/libsomething.so
pointing to /lib/libsomething.so.2
on machine B.
The loader (run ldd
) will choose unversioned symlinks regardless where it points to:
libsomething.so => /lib/libsomething.so (0xNNNNNNNN)
on machine A;
libsomething.so => /lib/libsomething.so (0xNNNNNNNN)
on machine B.
Linux dynamic loader (ld.so
) resolves libraries based on their soname value written in the executable (ELF NEEDED
). The value is copied from library file (ELF SONAME
) while building the executable. As long as there is a symlink on the target system matching the soname recorded in the executable, the library pointed by this symlink will be loaded.
Let's run through your setup and show commands to verifing assumptions.
I used Fedora 18 X86_64
for the test and adjusted output to i686
for clarity.
Compile both libsomething.so.1
and libsomething.so.2
. Make sure SONAME
is set to unversioned libsomething.so
:
readelf -a libsomething.so.1 | grep SONAME
0xNNNNNNNN (SONAME) Library soname: [libsomething.so]
readelf -a libsomething.so.2 | grep SONAME
0xNNNNNNNN (SONAME) Library soname: [libsomething.so]
Install the libraries into their respective machines under /lib/
directory. Run ldconfig -v
on both machines and verify the output.
ldconfig -v 2>&1 | grep something
libsomething.so -> libsomething.so.1 (changed)
ldconfig -v 2>&1 | grep something
libsomething.so -> libsomething.so.2 (changed)
Compile executable and make sure that it refers to the same soname without version in NEEDED
.
readelf -a executable | grep NEEDED
0xNNNNNNNN (NEEDED) Shared library: [libsomething.so]
You executable depends on unversioned libsomething.so
now. Copy executable to both machines and run ldd
against both copies.
ldd executable
libsomething.so => /lib/libsomething.so (0xNNNNNNNN)
The last output is the same on both machines as the executable was built with soname without version. This makes loader take unversioned symlinks on targets machines. And depending on the machine, the symlink can point to different implementation of the library libsomething.so.1
or libsomething.so.2
.