I am trying to understand how/why certain library files are dynamically loaded by the linker on Solaris. I am using ldd to see this (with the -s switch to see what paths are tried by the linker). As an example, if I run "ldd /usr/local/bin/isql -s" I notice that one of the libraries that is searched for is called "libodbc.so.1". I notice that this does NOT match a file it finds along the way called "libodbc.so". So, it finally resolves to a place where there is a symbolic link between "libodbc.so.1.0.0" and "libodbc.so.1". My question is - what is the significance of the ".1" here? Is it to indicate a version number? Why do some installers create these symbolic links, while others don't?
This question is not specific to Solaris.
When you install a shared library (or a piece of software that provides a shared library), you get three files, they all look similar but have different purposes.
libfoo.so.1.0.0‒ This is the (regular) data file. It contains the library itself. You could have multiple of these, with different versions. Inside this file, there is an ELF field called SONAME, which is set to
libfoo.so.1. On Linux, run
objdump -p libfoo.so.1.0.0 | grep SONAMEto find out.
libfoo.so.1.0.0‒ This is a symlink which is used when compiling software against libfoo. When you specify
-lfooto the linker, it will look for exactly
libfoo.sois never a regular file, it is always a symlink which points to the version of libfoo which you want to use for linking. In a complex build environment, you could have multiple versions of the library, and you use this symlink to choose, against which version you want to link.
libfoo.so.1.0.0‒ This is also a symlink, which is used when you run binaries that need your library. Remember the SONAME field I mentioned? When you link a binary against libfoo, the binary will record the SONAME of the library and will use it at runtime.
This setup allows you to have multiple versions of the same library installed alongside each other. Different binaries may require different versions of the library, and each binary will find the right version of the library. Usually, the SONAME of the library is changed by the upstream when there is a backward-incompatible API change. All the old binaries still use the old API, while newly linked binaries use the new one.
Some packaging projects, Debian would be one example, use different package names for different versions of a library. This allows you to install and uninstall each version of the shared library independently.
There are some edge cases. For example, dependencies between shared libraries can lead to two versions being pulled in at the same time. Consider:
foo → libbar.so.1, libbaz.so.1
libbar.so.1 → libbaz.so.1
Imagine that we install a new version of libbaz and recompile foo. Now we have:
foo → libbar.so.1, libbaz.so.2
libbar.so.1 → libbaz.so.1
At runtime, foo will load
libbar.so.1 will load
libbaz.so.1. See the problem? Two versions of libbaz are loaded at the same time. I'm not entirely sure what's the exact consequence in terms of the layout of the code in memory, but in practice this results in crashes.