Installing Shared Libraries

In the examples up to now, we created a shared library in a user-private directory, and then used the LD_LIBRARY_PATH environment variable to ensure that the dynamic linker searched that directory. Both privileged and unprivileged users may use this technique. However, this technique should not be employed in production applications. More usually, a shared library and its associated symbolic links are installed in one of a number of standard library directories, in particular, one of the following:

In most cases, copying a file into one of these directories requires superuser privilege.

After installation, the symbolic links for the soname and linker name must be created, usually as relative symbolic links in the same directory as the library file. Thus, to install our demonstration library in /usr/lib (whose permissions only allow updates by root), we would do the following:

$ su
Password:
# mv libdemo.so.1.0.1 /usr/lib
# cd /usr/lib
# ln -s libdemo.so.1.0.1 libdemo.so.1
# ln -s libdemo.so.1 libdemo.so

The last two lines in this shell session create the soname and linker name symbolic links.

The ldconfig(8) program addresses two potential problems with shared libraries:

The ldconfig program solves these problems by performing two tasks:

In order to correctly perform these actions, ldconfig expects libraries to be named according to the conventions described earlier (i.e., library real names include major and minor identifiers that increase appropriately from one library version to the next).

By default, ldconfig performs both of the above actions. Command-line options can be used to selectively inhibit either action: the -N option prevents rebuilding of the cache, and the -X option inhibits the creation of the soname symbolic links. In addition, the -v (verbose) option causes ldconfig to display output describing its actions.

We should run ldconfig whenever a new library is installed, an existing library is updated or removed, or the list of directories in /etc/ld.so.conf is changed.

As an example of the operation of ldconfig, suppose we wanted to install two different major versions of a library. We would do this as follows:

$ su
Password:
# mv libdemo.so.1.0.1 libdemo.so.2.0.0 /usr/lib
# ldconfig -v | grep libdemo
        libdemo.so.1 -> libdemo.so.1.0.1 (changed)
        libdemo.so.2 -> libdemo.so.2.0.0 (changed)

Above, we filter the output of ldconfig, so that we see just the information relating to libraries named libdemo.

Next, we list the files named libdemo in /usr/lib to verify the setup of the soname symbolic links:

# cd /usr/lib
# ls -l libdemo* | awk '{print $1, $9, $10, $11}'
lrwxrwxrwx libdemo.so.1 -> libdemo.so.1.0.1
-rwxr-xr-x libdemo.so.1.0.1
lrwxrwxrwx libdemo.so.2 -> libdemo.so.2.0.0
-rwxr-xr-x libdemo.so.2.0.0

We must still create the symbolic link for the linker name, as shown in the next command:

# ln -s libdemo.so.2 libdemo.so

However, if we install a new 2.x minor version of our library, then, since the linker name points to the latest soname, ldconfig has the effect of also keeping the linker name up to date, as the following example shows:

# mv libdemo.so.2.0.1 /usr/lib
# ldconfig -v | grep libdemo
        libdemo.so.1 -> libdemo.so.1.0.1
        libdemo.so.2 -> libdemo.so.2.0.1 (changed)

If we are building and using a private library (i.e., one that is not installed in one of the standard directories), we can have ldconfig create the soname symbolic link for us by using the -n option. This specifies that ldconfig should process only libraries in the directories on the command line and should not update the cache file. In the following example, we use ldconfig to process libraries in the current working directory:

$ gcc -g -c -fPIC -Wall mod1.c mod2.c mod3.c
$ gcc -g -shared -Wl,-soname,libdemo.so.1 -o libdemo.so.1.0.1 \
          mod1.o mod2.o mod3.o
$ /sbin/ldconfig -nv .
.:
        libdemo.so.1 -> libdemo.so.1.0.1
$ ls -l libdemo.so* | awk '{print $1, $9, $10, $11}'
lrwxrwxrwx libdemo.so.1 -> libdemo.so.1.0.1
-rwxr-xr-x libdemo.so.1.0.1

In the above example, we specified the full pathname when running ldconfig, because we were using an unprivileged account whose PATH environment variable did not include the /sbin directory.