Why can’t I install multiple versions of a shared library

dynamic-linkingpackage-managementshared libraryversion

There are often instances where a certain program will depend on library version x.y and another on x.z but, as far as I'm aware, no package manager will allow me to install both x.y and x.z. Sometimes they will allow both major versions (such as qt4 and qt5, which can be installed at the same time), but (seemingly) never minor versions.

Why is this? As in, what is the limiting factor that prevents it? I assume there must be a good reason for not allowing this seemingly useful functionality. E.g., is there not a field to indicate what version to load when loading a shared object and thus no way for Linux to know how to decide which to load? Or is there really no reason for it? Like all minor versions are supposed to be compatible anyway or something?

Best Answer

Actually, you can install multiple versions of a shared library if it's done properly.

Shared libraries are usually named as follows:

lib<name>.so.<api-version>.<minor>

Next, there are symlinks to the library under the following names:

lib<name>.so
lib<name>.so.<api-version>

When a developer links against the library to produce a binary, it is the filename that ends in .so that the linker finds. There can indeed be only one of those installed at a time for any given <name> but that only means that a developer cannot target multiple different versions of a library at the same time. With package managers, this .so symlink is part of a separate -dev package which only developers need install.

When the linker finds a file with a name ending in .so and uses it, it looks inside that library for a field called soname. The soname advises the linker what filename to embed into the resulting binary and thus what filename will be sought at runtime. The soname is supposed to be set to lib<name>.so.<api-version>.

Therefore, at run time, the dynamic linker will seek lib<name>.so.<api-version> and use that.

The intention is that:

  • <minor> upgrades don't change the API of the library and when the <minor> gets bumped to a higher version, it's safe to let all the binaries upgrade to the new version. Since the binaries are all seeking the library under the lib<name>.so.<api-version> name, which is a symlink to the latest installed lib<name>.so.<api-version>.<minor>, they get the upgrade.
  • <api-version> upgrades change the API of the library, and it is not safe to let existing binary applications use the new version. In the case that the <api-version> is changed, since those applications are looking for the name lib<name>.so.<api-version> but with a different value for <api-version>, they will not pick up the new version.

Package managers don't often package more than one version of the same library within the same distribution version because the whole distribution, including all binaries that make use of the library, is usually compiled to use a consistent version of every library before the distribution is released. Making sure that everything is consistent and that everything in a distribution is compatible with everything else is a big part of the workload for distributors.

But you can easily end up with multiple versions of a library if you've upgraded your system from one version of your distritution to another and still have some older packages requiring older library versions. Example:

  • libmysqlclient16 from an older Debian, contains libmysqlclient.so.16.0.0 and symlink libmysqlclient.so.16.
  • libmysqlclient18 from current Debian, contains libmysqlclient.so.18.0.0 and symlink libmysqlclient.so.18.
Related Question