Book: LPI Linux Certification in a Nutshell
Section: Chapter 14.  Linux Installation and Package Management (Topic 2.2)



14.4 Objective 4: Manage Shared Libraries

When a program is compiled under Linux, many of the functions required by the program are linked from system libraries that handle disks, memory, and other functions. For example, when printf( ) is used in a program, the programmer doesn't provide the printf( ) source code, but instead expects that the system already has a library containing such functions. When the compiler needs to link the code for printf( ), it can be found in a system library and copied into the executable. A program that contains executable code from these libraries is said to be statically linked because it stands alone, requiring no additional code at runtime.

Statically linked programs can have a few liabilities. First, they tend to get large, because they include executables for all of the library functions linked into them. Also, memory is wasted when many different programs running concurrently contain the same library functions. To avoid these problems, many programs are dynamically linked. Such programs utilize the same routines but don't contain the library code. Instead, they are linked into the executable at runtime. This dynamic linking process allows multiple programs to use the same library code in memory and makes executable files smaller. Dynamically linked libraries are shared among many applications and are thus called shared libraries. A full discussion of libraries is beyond the scope of the LPIC Level 1 exams. However, a general understanding of some configuration techniques is required.

14.4.1 Shared Library Dependencies

Any program that is dynamically linked will require at least a few shared libraries. If the required libraries don't exist or can't be found, the program will fail to run. This could happen, for example, if you attempt to run an application written for the GNOME graphical environment but haven't installed the required GTK+ libraries. Simply installing the correct libraries should eliminate such problems. The ldd utility can be used to determine which libraries are necessary for a particular executable.

ldd

Syntax

ldd programs

Description

Display shared libraries required by each of the programs listed on the command line. The results indicate the name of the library and where the library is expected to be in the filesystem.

Example

In Objective 3, a trivial executable called hw was created. Despite its small size, however, hw requires two shared libraries:

# ldd /home/jdean/hw
/home/jdean/hw:
     libc.so.6 => /lib/libc.so.6 (0x40018000)
     /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

The bash shell requires three shared libraries:

# ldd /bin/bash
/bin/bash:
     libtermcap.so.2 => /lib/libtermcap.so.2 (0x40018000)
     libc.so.6 => /lib/libc.so.6 (0x4001c000)
     /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

14.4.2 Linking Shared Libraries

Dynamically linked executables are examined at runtime by the shared object dynamic linker, ld.so. This program looks for dependencies in the executable being loaded and attempts to satisfy any unresolved links to system-shared libraries. If ld.socan't find a specified library, it fails, and the executable won't run.

To illustrate this, let's assume that the printit( ) function from the hw example in Objective 3 is moved to a shared library instead of being compiled into the program. The custom library is called libprintit.so and stored in /usr/local/lib. hw is reconfigured and recompiled to use the new library.[8] By default, ld.sodoesn't expect to look in /usr/local/lib for libraries, and fails to find printit( ) at runtime:

[8] Though not complicated, the compilation of libprintit.so and hw is beyond the scope of the LPIC Level 1 exams.

# ./hw
./hw: error in loading shared libraries: libprintit.so: 
   cannot open shared object file: No such file or directory

To find the new library, ld.so must be instructed to look in /usr/local/lib. There are a few ways to do this. One simple way is to add a colon-separated list of directories to the shell environment variable LD_LIBRARY_PATH, which will prompt ld.soto look in any directories it finds there. However, this method may not be appropriate for system libraries, because users might not set their LD_LIBRARY_PATH correctly.

To make the search of /usr/local/lib part of the default behavior for ld.so, files in the new directory must be included in an index of library names and locations. This index is /etc/ld.so.cache. It's a binary file, which means it can be read quickly by ld.so. To add the new library entry to the cache, its directory is first added to the ld.so.conf file, which contains directories to be indexed by the ldconfig utility.

ldconfig

Syntax

ldconfig [options] lib_dirs

Description

Update the ld.so cache file with shared libraries specified on the command line in lib_dirs, in trusted directories /usr/lib and /lib, and in the directories found in /etc/ld.so.conf.

Frequently used options

-p

Display the contents of the current cache instead of recreating it.

-v

Verbose mode. Display progress during execution.

Example 1

Examine the contents of the ld.so library cache:

# ldconfig -p
299 libs found in cache `/etc/ld.so.cache' (version 1.7.0)
    libzvt.so.2 (libc6) => /usr/lib/libzvt.so.2
    libz.so.1 (libc6) => /usr/lib/libz.so.1
    libz.so.1 (ELF) => /usr/i486-linux-libc5/lib/libz.so.1
    libz.so (libc6) => /usr/lib/libz.so
    libx11amp.so.0 (libc6) => /usr/X11R6/lib/libx11amp.so.0
    libxml.so.0 (libc6) => /usr/lib/libxml.so.0 
(... listing continues ...)

Example 2

Look for a specific library entry in the cache:

# ldconfig -p | grep "printit"
    libprintit.so (libc6) => /usr/local/lib/libprintit.so

Example 3

Rebuild the cache:

# ldconfig

After /usr/local/lib is added, ld.so.conf might look like this:

/usr/lib
/usr/i486-linux-libc5/lib
/usr/X11R6/lib
/usr/local/lib

Next, ldconfig is run to include libraries found in /usr/local/lib in /etc/ld.so.cache :

# ldconfig
# ./hw
Hello, world

Now the hw program can execute correctly because ld.so can find libprintit.so in /usr/local/lib. It is important to run ldconfig after any changes in system libraries to be sure that the cache is up-to-date.