views:

95

answers:

2

When I do ls -l in /usr/lib I see lots of libs with "sameName.so.*.*" extension.

  1. What is the significance of these extensions?
  2. Why softlinks are created? what are their use?

One example will help a lot in understanding.

+7  A: 

This is a trick used to version shared object files. It's a way of avoiding the dreaded DLL hell which came about because of lazy linking.

The advantage of lazy linking (or late binding) is that components of your executable can be changed without actually re linking those executables. This allows for bug fixes in third party components without having to ship a new executable, among other things.

The disadvantage is exactly the same as the advantage. Your executable can find that assumptions it made about the underlying libraries have been changed and this is likely to cause all sorts of issues.

Versioning of shared objects is one way to avoid this. Another would be to not share objects at all but that also has pros and cons which I won't get into here.

By way of example, let's say you have version 1 of xyz.so. You have a file and a symbolic link to that file:

pax> ls -al xyz*
-rw-r--r--  1 pax paxgroup    12345 Nov 18  2009 xyz.so.1
lrwxrwxrwx  1 pax paxgroup        0 Nov 18  2009 xyz.so -> xyz.so.1

Now, when you create an executable file exe1, linking it with xyz.so, it will follow the symbolic link so that it stores xyz.so.1 in the executable as the thing it needs to load at runtime.

That way, when you upgrade the shared library thus:

pax> ls -al xyz*
-rw-r--r--  1 pax paxgroup    12345 Nov 18  2009 xyz.so.1
-rw-r--r--  1 pax paxgroup    67890 Nov 18  2009 xyz.so.2
lrwxrwxrwx  1 pax paxgroup        0 Nov 18  2009 xyz.so -> xyz.so.2

your original executable exe1 will still load version 1 of the shared object.

However, any executables you create now (such as exe2) will be linked with version 2 of the shared object.


The actual implementation details may vary somewhat (I'm basing my answer on earlier UNIXes and Linux appears to do versioning a little more intelligently than just following symbolic links). IBM developerWorks has a nice article on how it's done here.

When you create a shared object, you give it both a real name and an soname. These are used to install the shared object (which creates both the object and a link to it).

So you can end up with the situation:

pax> ls -al xyz*
-rw-r--r--  1 pax paxgroup    12345 Nov 18  2009 xyz.so.1.5
lrwxrwxrwx  1 pax paxgroup        0 Nov 18  2009 xyz.so.1 -> xyz.so.1.5
lrwxrwxrwx  1 pax paxgroup        0 Nov 18  2009 xyz.so -> xyz.so.1

with xyz.so.1.5 possessing the SONAME of xyz.so.1.

When the linker links in xyz.so, it follows the links all the way to xyz.so.1.5 and uses its SONAME of xyz.so.1 to store in the executable. Then, when you run the executable, it tries to load xyz.so.1 which will point to a specific xyz.so.1.N (not necessarily version 1.5).

So you could install xyz.so.1.6 and update the xyz.so.1 link to point to it instead and already-linked executables would use that instead.

One advantage of this multi-layer method is that you can have multiple potentially incompatible libraries of the same name (xyz.so.1.*, xyz.so.2.*) but, within each major version, you can freely upgrade them since they're supposed to be compatible.

When you link new executables:

  • Those linking with xyz.so will get the latest minor version of the latest major version.
  • Others linking with xyz.so.1 will get the latest minor version of a specific major version.
  • Still others linking with xyz.so.1.2 will get a specific minor version of a specific major version.
paxdiablo
Actually in the executable it stores the value of library's `SONAME`, which happends to be the same as `xyz.so.1`. `xyz.so.1` may be a symlink itself and resolve to a binary-compatible library with a different patch level, e.g. `xyz.so.1.0` or `xyz.so.1.1`.
Alex B
+5  A: 

It's a versioning scheme for shared libraries. Every library should have 3 names:

  1. Real name: the actual library name, libfoo.so.1.2.3
  2. "SONAME": the name recorded in the executable, and the name dynamic linker looks for, libfoo.so.1.2. This name is actually written inside the library binary itself, and will be recorded in the executable at link time. It is usually a symlink to library's real name (usually latest version).
  3. Linker name: the name you give to the linker when building your program. Usually links to the latest SONAME.

Example

Say you have libfoo version 1 installed: libfoo.so -> libfoo.so.1.0 -> libfoo.so.1.0.0. You build your program bar with -lfoo. it now links to libfoo and will load libfoo.so.1.0 at runtime due to SONAME. Then you upgrade to a patched but binary-compatible libfoo.so.1.0.1 by replacing real binary. bar still links to libfoo.so.1.0 and doesn't need to be rebuilt.

Now imagine you want to build a new program baz that takes advantage of incompatible changes in libfoo v1.1. You install new version and your system now have two versions installed in parallel:

  1. libfoo.so.1.0 -> libfoo.so.1.0.1
  2. libfoo.so -> libfoo.so.1.1 -> libfoo.so.1.1.0

Note linker name was updated to the latest version (this is the version corresponding to the headers you installed in /usr/include).

You build baz, and it links to libfoo.so and loads libfoo.so.1.1 at runtime. Not that bar still runs against libfoo.so.1.0 and doesn't need to be updated.

Alex B