Send in your Unix questions today!
See additional Unix tips and tricks
The use of dynamically linked libraries makes a lot of sense when it comes to keeping system binaries small, but can generate some head-scratching problems when you are trying to install or run software and the required libraries appear to be missing. Let's take a quick look at what dynamic libraries are and how you can work around some of the common problems you might run into that involve their use.
First, dynamically linked libraries are collections of programs or routines that any number of executables on your system are likely to use. They provide generally useful functions so that other programs don't have to build all the functionality that they need from scratch -- maybe some kind of I/O, type conversion or mathematical function. Programs that use shared libraries require less RAM. They can include a reference to a library, after all, but may not actually use it. Whether a particular library is needed at run-time depends on what the program is being asked to do by its users.
If you want to find out which libraries a particular executable uses, use the ldd command. Ldd lists the dynamic dependencies of executable files or shared objects. For example, if we were to ask ldd about the date command, we would see something like this:
# ldd /usr/bin/date
libc.so.1 => /usr/lib/libc.so.1
libdl.so.1 => /usr/lib/libdl.so.1
/usr/platform/SUNW,UltraAX-i2/lib/libc_psr.so.1
If we were to ask about the shared object file, libglib.so, we see pretty much the same thing. The two-column output includes the names as specified in the executable (left column) and the full path names (right column) that the system will use to locate the shared libraries at run-time.
# ldd libglib.so
libc.so.1 => /usr/lib/libc.so.1
libdl.so.1 => /usr/lib/libdl.so.1
/usr/platform/SUNW,UltraAX-i2/lib/libc_psr.so.1
We can see from the output above that both the date command and the libglib shared object file require three additional libraries. In the listing, we can see that the first two paths, as specified in the executable, are relative. At run time, the first instance of these libraries (e.g., libc.so.1) that the dynamic linker/loader finds (as configured through the LD_LIBRARY_PATH and runtime linking) is the one that will be used. Given the environment at the time the example ldd commands were run, the libraries in /usr/lib were selected.
The third library listed is an absolute dependency. For this, the library will not look anywhere but in the directory displayed for the libc_psr.so.1 file. When you see a reference like this one that refers to /usr/platform, you can safely assume that this use of the absolute dependency ensures that the library will not function if it a program tries to use it on a system with a different architecture.
Now, let's look at the required libraries for an altogether different binary.
# ldd /usr/j2sdk1.4.2_05/jre/lib/sparcv9/libnio.so
libjvm.so => (file not found)
libsocket.so.1 => /usr/lib/64/libsocket.so.1
librt.so.1 => /usr/lib/64/librt.so.1
libdl.so.1 => /usr/lib/64/libdl.so.1
libjava.so => /usr/j2sdk1.4.2_05/jre/lib/sparcv9/libjava.so
libnet.so => /usr/j2sdk1.4.2_05/jre/lib/sparcv9/libnet.so
libc.so.1 => /usr/lib/64/libc.so.1
libnsl.so.1 => /usr/lib/64/libnsl.so.1
libaio.so.1 => /usr/lib/64/libaio.so.1
libjvm.so => (file not found)
libverify.so => /usr/j2sdk1.4.2_05/jre/lib/sparcv9/libverify.so
libjvm.so => (file not found)
libmp.so.2 => /usr/lib/64/libmp.so.2
libjvm.so => (file not found)
/usr/platform/SUNW,UltraAX-i2/lib/sparcv9/libc_psr.so.1
In the ldd command and output shown above, we are asking about a particular JDK library. Notice, however, that we have encountered four "file not found" errors, telling us the libnio.so library is not going to work -- at least not given the current library path.
These "file not found" errors could go away, however, if we were to find and add a directory that contains the missing libraries to our library path:
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/j2sdk1.4.2_05/jre/lib/sparcv9
After adding this directory to our library path, let's run the ldd command again:
# ldd /usr/j2sdk1.4.2_05/jre/lib/sparcv9/libnio.so
libjvm.so => /usr/j2sdk1.4.2_05/jre/lib/sparcv9/server/libjvm.so
libsocket.so.1 => /usr/lib/64/libsocket.so.1
librt.so.1 => /usr/lib/64/librt.so.1
libdl.so.1 => /usr/lib/64/libdl.so.1
libjava.so => /usr/j2sdk1.4.2_05/jre/lib/sparcv9/libjava.so
libnet.so => /usr/j2sdk1.4.2_05/jre/lib/sparcv9/libnet.so
libc.so.1 => /usr/lib/64/libc.so.1
libCrun.so.1 => /usr/lib/64/libCrun.so.1
libthread.so.1 => /usr/lib/64/libthread.so.1
libnsl.so.1 => /usr/lib/64/libnsl.so.1
libm.so.1 => /usr/lib/64/libm.so.1
libsched.so.1 => /usr/lib/64/libsched.so.1
libaio.so.1 => /usr/lib/64/libaio.so.1
libverify.so => /usr/j2sdk1.4.2_05/jre/lib/sparcv9/libverify.so
libw.so.1 => /usr/lib/64/libw.so.1
libmp.so.2 => /usr/lib/64/libmp.so.2
/usr/platform/SUNW,UltraAX-i2/lib/sparcv9/libc_psr.so.1
Now, we see that the errors have disappeared. Ldd has found the required libraries in the added directory.
Another problem you might run into is when a library is found, but turns out to be a different version of the library than the executable requested -- as the error message on the first line of output indicates.
# ldd php
libc.so.1 (SUNW_1.22) => (version not found)
libm.so.2 => (file not found)
"Version not found" errors could indicate that your system libraries are out of date, but you might have the required versions in a different directory and have to adjust your LD_LIBRARY_PATH. These errors could also indicate that the application or package that you are trying to load is meant for a different version of the OS than that which is installed. To view the version information of a particular library, use the pvs command. Here is output from pvs on a Solaris 9 system:
# pvs /usr/lib/libc.so.1 | head -5
libdl.so.1 (SUNW_1.4, SUNWprivate_1.1);
libc.so.1;
SUNW_1.21.2;
SUNW_1.21.1;
SUNW_1.21;
Here's the same command on Solaris 10:
# pvs /usr/lib/libc.so.1 | head -5
libc.so.1;
SUNW_1.22.1;
SUNW_1.22;
SUNW_1.21.3;
SUNW_1.21.2;
The errors generated by the "ldd php" command, shown above, if generated on a Solaris 9 system, would be telling you that you are trying to use a version of php that was built for Solaris 10.
How Does ldd Work?
The ldd command actually uses the runtime linker, ld.so.1, to generate its dependency lists. Ld.so.1, in turn, inspects each library and prepares as it would if it was preparing for a running process. This allows us to be sure that its output reflects what will actually happen at run time when the required libraries are requested.
Statically linked executables will, obviously, not have any dynamic dependencies. If you ask ldd about one of these, you will get a response like that shown below:
# ldd /usr/sbin/static/cp
ldd: /usr/sbin/static/cp: file is not a dynamic executable or shared object
These executables don't require any external libraries and are, thus, truly "standalone" binaries.