A Little About Linux: Shared Libraries

What are Libraries?  Places full of books perhaps?  Ah, we have a comedian in our midst!  Well in computing terms, when programs are written, they quite often contain functionality which is very useful to other programs.  Now, each programmer could re-write that useful bit of code within their own programs, but that isn't very efficient is it?  So, this common code is contained in a library and when an executable requires these extra bits of functionality, these libraries are connected or linked to it in one of two ways;

Statically (lib.a) - The program contains the library code within its own main file.  The drawback with this method is that the resultant file is large and therefore consumes large amounts of disc space and RAM when loaded.  Also, the greater the number of other applications that use this library, the more resources are used and, if the library code needs changing, each program using the code must be re-linked.
Dynamic (lib.so) - Like a Dynamic Linked Library in Windows, they are a much more useful and efficient way of using shared functionality. This method means that the required libraries are loaded into RAM only when the program needs them.  It reduces the file size of the executable, allows the library to only run in memory once whilst simultaneously being used by multiple programs, and if the functionality changes or is improved in the library, it only needs to be updated once.  However, there are also some downsides with using Dynamic Libraries; 1) If you make a change to the shared library and obviously many programs use this library, this change may be incompatible with some of the programs that use it, 2) Configuration files and environmental variables must be set correctly so that the programs can locate the libraries, 3) if shared libraries get overwritten accidentally, it could cause severe system issues or even result in a system failing to boot.

Getting Programs to Find Libraries
To permanently set the library path location on a system wide basis, the /etc/ld.so.conf file is used.  This file may have a number of lines, all of which point to where libraries are located, or it may only have an include line which adds other files as part of the same file;

include /etc/ld.so.conf.d/*.conf

In this case, all files in the /etc/ld.so.conf.d/ directory are also added to the path, as an example, the contents of the directory might appear like this;

kernel-2.6.32-431.17.1.el6.x86_64.conf                 
kernel-2.6.32-431.23.3.el6.centos.plus.x86_64.conf
kernel-2.6.32-431.20.3.0.1.el6.centos.plus.x86_64.conf  
kernel-2.6.32-431.el6.x86_64.conf

kernel-2.6.32-431.20.3.el6.centos.plus.x86_64.conf      
mysql-x86_64.conf

/lib and /usr/lib are also automatically included as library locations by default along with those locations specified above.  If the path is changed using this method,  the Dynamic Linker ldconfig must be run afterwards.

In practice, path locations are very rarely changed system wide, more often than not, they only need to be set via an environmental variable (LD_LIBRARY_PATH).  The path can be set by using; 

$ export LD_LIBRARY_PATH=/path/to/library:/another/path/library

They are added to the start of the search path and take precedence over all other paths specified.

If when you launch an application, and an error of the type; "Error while loading shared libraries: lib.so.1" appears, it should be fairly obvious that the lib.so.1 library can't by found by the application.  But what if you know that this library absolutely, definitely is installed  Well, in this case start by adding the path using the LD_LIBRARY_PATH environmental 
variable as shown above but if this doesn't work, you may need to create a symbolic link to the library (especially if the library naming convention is slightly different to the one the application is looking for) e.g. the app looks for lib.so.1 but lib.so.1.1 is installed... you will need to perform this bit of magic;

# ln -s lib.so.1.1 lib.so.1

This means create a symbolic link called lib.so.1 at the current location, (so the executable can find it when it runs) but point it to the actual path of lib.so.1.1 (which is where the library actually is).  ldconfig must then be run.

Management Tools for Libraries
There are two tools for managing libraries, one of which we have already touched on;

ldd and ldconfig

ldd is used to find what libraries an executable file uses and in this example for the df (free disc space) command you can see the library name and full path to the library (it's best used with the verbose switch);

# ldd -v /bin/df

linux-vdso.so.1 =>  (0x00007fffeadc5000)
libc.so.6 => /lib64/libc.so.6 (0x00007f69a2228000)
/lib64/ld-linux-x86-64.so.2 (0x00007f69a25c7000)

Version information:
/bin/df:

libc.so.6 (GLIBC_2.3) => /lib64/libc.so.6
libc.so.6 (GLIBC_2.4) => /lib64/libc.so.6
libc.so.6 (GLIBC_2.3.4) => /lib64/libc.so.6
libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
/lib64/libc.so.6:
ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2

You can even use ldd to find the dependencies of dependencies i.e. what are the dependences of the libraries, that the executable requires.

With ldconfig, you may have already gathered by its use in the previous section, that it operates to either clear something or reload something, and you'd be correct in that assumption.  Linux uses a cached list of paths to the libraries, which are not updated unless this command is run.  It takes multiple options but if you just want to rebuild the cache, just use it in verbose mode;

# ldconfig -v

Or you can print the contents of the cache without affecting it by using;

# ldconfig -p

When an RPM or DEB package is installed, the ldconfig command is run automatically at the end of this procedure.

No comments: