Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Version numbers in shared object files

I'm building a shared object file from a group of C++ source files using GCC. All the example tutorials on building .so files show the file created with a version number after the .so suffix. For example:

gcc -shared -Wl,-soname,libmean.so.1 -o libmean.so.1.0.1  calc_mean.o

This would produce the .so file libmean.so.1.0.1

Additionally, if I browse the /usr/lib directory on my local machine, I see that many of the .so files have version numbers at the end.

However, when I compile a shared object file and place it in /usr/lib, the linker is unable to find it if I put a version number at the end. If I remove the version number, it works fine. I really don't care about putting a version number or not, I just don't understand why this seems to be a common convention, and yet this causes the shared library to not work with the linker. So, what's going on here? Why is there a convention to place the version number at the end of an .so file name?

like image 262
Channel72 Avatar asked Apr 22 '11 21:04

Channel72


1 Answers

The version number is appended so you can have multiple incompatible library versions coexisting in the system. You should increment the major version number (the number in soname) every time you change the API in an incompatible way (assuming the previous version is installed and used in the system, of course).

The 2nd and 3rd numbers in the file name allows for multiple minor revisions of the library in the system, switchable system-wide with a simple symlink update.

At link time you can give the .so file name as a linker argument, instead of -l option. ldd is smart enough to extract the soname from it, the binary linked this way uses it to find the library.

For example, let's compile the library and test binary using it:

czajnik@czajnik:~/z$ gcc -shared -Wl,-soname,libtest.so.2 -o libtest.so.2.3.4  a.c 
czajnik@czajnik:~/z$ gcc -o test b.c -L. ./libtest.so.2.3.4

You can use ldd to verify, that the binary now looks for libtest.so.2:

czajnik@czajnik:~/z$ LD_LIBRARY_PATH=. ldd ./test
    linux-gate.so.1 =>  (0x002c1000)
    libtest.so.2 => not found
    libc.so.6 => /lib/libc.so.6 (0x00446000)
    /lib/ld-linux.so.2 (0x00a28000)

It obviously can't find it, but that's what the symlink is for:

czajnik@czajnik:~/z$ ln -s libtest.so.2.3.4 libtest.so.2
czajnik@czajnik:~/z$ LD_LIBRARY_PATH=. ldd ./test
    linux-gate.so.1 =>  (0x00d75000)
    libtest.so.2 => ./libtest.so.2 (0x00e31000)
    libc.so.6 => /lib/libc.so.6 (0x00a5e000)
    /lib/ld-linux.so.2 (0x00378000)

Update: All of the above is true, yet I wasn't myself aware of the meaning of the 3rd component of the version number. Until recently, I believed it is simply a patch number (or similar thing). Wrong! For libtool it has a special meaning.

The 3rd component turned out to be age field, which says how many major versions are backward compatible with the current one.

Recommended reading:

  • Idiot's Guide to ABI Versioning
  • Libtool's versioning system
like image 77
Code Painters Avatar answered Oct 26 '22 11:10

Code Painters