What is a .so.2 file?

Usually when you build shared objects (.so) then you also take care of versions by adding suffixes such as mylib.so.2.3.1. To make sure your programs can load this lib or other later versions you create links with names

mylib.so -> mylib.so.2.3.1
mylib.so.2 -> mylib.so.2.3.1
mylib.so.2.3 -> mylib.so.2.3.1

So, everything after .so represents version.sub-version.build (or similar) Also, it is possible for more than one version of the same lib to coexist with this scheme, and all that is necessary to switch programs to using a particular version is to have the appropriate links in place.


Dynamically linked ELF binary (whether another library or an executable) uses shared-object name or soname to identify the library that the executable should be linked against upon execution.

When a library created as an ELF shared library, the compile-time link editor inserts a DT_SONAME field in the executable which the library's SONAME into the library itself. The DT_SONAME is defined in the ELF standard as:

This element holds the string table offset of a null-terminated string, giving the name of the shared object. The offset is an index into the table recorded in the DT_STRTAB entry. See ‘‘Shared Object Dependencies’’ below for more information about these names.

So now when an executable is create the SONAME is embedded into it. When when the executable is run is used by the linker to look for the library in the files in the predifined locations for dynamic library. The predefined location in windows would be wherever DLLs reside. In Linux and Mac OS X and other System V compatible systems they would be /lib and /usr/lib and possibly other spots, it depends on the linker used, and can be defined in linkers own configurations.

In all events the linker looks to see if the library named in soname entry is present in any of those locations, if it is it will use it.

Note that the standard says that the soname is a STRING and the versioning conventions became a defacto standard after the fact and goes something like this:

Make the soname to be libmyname.so.A and make the library filename be libmyname.so.A.B or libmyname.so.A.B.C (under MacOSX it's libmyname.A.B.dylib). Create a softlink from libmyname.so.A.B[.C]? to libmyname.so.A.

A is kept the same while the library's ABI stays the same.

B (or B.C) becomes the minor version.

Under Linux it's really common that the library version would be the same as the package version number. This has its pros and cons.

libtool formalization

GNU libtool is used a lot to build dynamic libraries, and has a more formal versioning system and has strong logic for it. The libtool versioning system for sonames works very well and is adopted by complex libraries to keep things straight.

Under libtool, the versioning is as under:

libmylib-current.release.age

Under libtool the idea is that as libraries evolve they will add and remove functionality.

Let's say you are developing a library. Start by using a version as 0.0.0.

Now let's say you fix a few bugs, you would only increase the release number.

So new name would be come libmylib.0.1.0 or libmylib.0.2.0 etc.. for every release that just fixes bugs but doesn't change any of the ABI.

Along the way you say. Ugh! I could've done this subfunctionality better, So you add a new set of functions to do something better, but because others are still using your library so you still leave the old (deprecated) functionality in there.

The rules are as under:

  1. Start with version information of ‘0:0:0’ for each libtool library.

  2. Update the version information only immediately before a public release of your software. More frequent updates are unnecessary, and only guarantee that the current interface number gets larger faster.

  3. If the library source code has changed at all since the last update, then increment revision (‘c:r:a’ becomes ‘c:r+1:a’).

  4. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0.

  5. If any interfaces have been added since the last public release, then increment age.

  6. If any interfaces have been removed or changed since the last public release, then set age to 0.

You can read more about it in the libtool documentation

Update ...

The following was a comment that my explanation has an error. It does not, which, requires a bit more detail than can be put into an answer comment, so see below.

Original objection

There is an error here: on linux, the version is of the form libmylib.(current-age).release.age, where the parentheses indicate an expression to be evaluated. For example GLPK 4.54 with current:revision:age = 37:1:1 on linux installs the library file libglpk.so.36.1.1. For more info, see, e.g., <autotools.io/libtool/version.html>.

Rebuttal

TLDR: autotools.io's not authortative source. Explanation

Whilst the Flameeyes is an amazing developer and he is one of Gentoo maintainers, it was he who made the mistake, and created a "rule of thumb" loose interpretation of the libtool spec. While this is not going to break systems 99% of the time, if we were to follow the ad-hoc way of updating current:

The rules of thumb, when dealing with these values are:

Always increase the revision value.

Increase the current value whenever an interface has been added, removed or changed.

Increase the age value only if the changes made to the ABI are backward compatible.

he then goes on to say that maintaining multiple versions of Gtk it would be best to just append the library version into the library NAME and simply dump the version number. (as they do in GTK+):

In this situation, the best option is to append part of the library's version information to the library's name, which is exemplified by Glib's libglib-2.0.so.0 soname. To do so, the declaration in the Makefile.am has to be like this:

lib_LTLIBRARIES = libtest-1.0.la

libtest_1_0_la_LDFLAGS = -version-info 0:0:0

Well that's just crockpot approach to mucking up the power of dynamic linking and symbol resolution versioning completely moot!. He's saying just turn it off. Horse boogers! No wonder even experienced developers have had a hard time building and maintaining open source projects and we are constantly running into binaries dying every time new versions of libraries are installed (because they clobber each other).

The libtool versioning approach is VERY WELL THOUGHT OUT. It is an algorithm and its steps are ordered instructions 1 to 6 are to be followed every time there is an update to the code of a dynamic linked library.

For new and current developers, please read them carefully and visualize what will happen to the library version number throughout the life of your amazing software. If you do you will notice that every piece of previously linked software will always use the most current and accurate version of your amazing library correctly, and none of them will ever clobber or stomp on each other, AND you never have to add a blooming number in the name of your library (unless it's for pleasure or esthetics).