When a program or application start on Linux, shared libraries are loaded. So if the shared library is installed properly in the system, all programs that start afterwards automatically use the new shared library. In managing your system’s applications, you need to understand libraries and, more specifically, shared libraries.

In this guide, we will look at how to manage shared libraries on Linux.
Library Principles
A collection of items, such as program functions is called system library. Self-contained code modules that perform a specific task within an application, such as opening and reading a data file are called functions.
There is an advantage of splitting functions into separate library files is that multiple applications that use the same functions can share the same library files. These files full of functions make it easier to distribute applications.
Linux supports two different types of libraries;
- Static libraries or Statically linked libraries
These are libraries which are loaded into an application when it is compiled.
- Shared libraries or Dynamic libraries
These are library functions which are loaded into memory and bound to the application when the program is launched.
On Linux/Unix systems, like application packages, library files have naming conventions. A shared library file uses the following filename format:
libLIBRARYNAME.so.VERSION
Locating Library Files
In locating library files, the system will search for the function’s library file in a specific order when a program is using a shared function in directories stored within:
- LD_LIBRARY_PATH environment variable
- Program’s PATH environment variable
- /etc/ld.so.conf.d/ folder
- /etc/ld.so.conf file
- /lib/ and /usr/lib/ folders
Note: The order of no. 3 & 4 may alternate on your system. The reason is because the /etc/ld.so.conf
file loads configuration files from the /etc/ld.so.conf.d/
folder.
Displaying the /etc/ld.so.conf
file contents on Linux:
$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
Files listing:
$ ls -1 /etc/ld.so.conf.d/
fakeroot-x86_64-linux-gnu.conf
libc.conf
x86_64-linux-gnu.conf
It is important to know that:
- The /lib*/ folders, such as /lib/ and /lib64/,are for libraries needed by system utilities that reside in the /bin/ and /sbin/ directories
- The /usr/lib*/ folders, such as /usr/lib/ and /usr/lib64/, are for libraries needed by additional software, such as database utilities like MariaDB.
Files within the /etc/ld.so.conf.d/ folder contains a shared library directory name and inside that directory are the shared library files needed by an application.
Looking at the /etc/ld.so.conf.d/ file contents on Ubuntu:
$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf
# Multiarch support
/usr/local/lib/x86_64-linux-gnu
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
Listing:
$ ls /usr/lib/x86_64-linux-gnu
libpytalloc-util.cpython-38-x86-64-linux-gnu.so.2
libpytalloc-util.cpython-38-x86-64-linux-gnu.so.2.3.0
libsamba-policy.cpython-38-x86-64-linux-gnu.so.0
libsamba-policy.cpython-38-x86-64-linux-gnu.so.0.0.1
Loading Shared Libraries Dynamically
Dynamic linker also called dynamic linker/loader is responsible for finding the program’s needed library functions when a program is started. After they are located, the dynamic linker will copy them into memory and bind them to the program.
The dynamic linker executable has a name like ld.so and ld-linux.so* or you may use locate
command to find the right name based on your distribution, in my case it is Ubuntu distro.
Locating the dynamic linker executable on Ubuntu.
$ locate ld-linux
/snap/core/10859/lib/ld-linux.so.2
/snap/core/10859/lib/i386-linux-gnu/ld-linux.so.2
/snap/core/10859/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/snap/core/10859/lib64/ld-linux-x86-64.so.2
/snap/core/10908/lib/ld-linux.so.2
/snap/core/10908/lib/i386-linux-gnu/ld-linux.so.2
/snap/core/10908/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/snap/core/10908/lib64/ld-linux-x86-64.so.2
/snap/core18/1932/lib/ld-linux.so.2
/snap/core18/1932/lib/i386-linux-gnu/ld-linux.so.2
/snap/core18/1932/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/snap/core18/1932/lib64/ld-linux-x86-64.so.2
/snap/core18/1988/lib/ld-linux.so.2
/snap/core18/1988/lib/i386-linux-gnu/ld-linux.so.2
/snap/core18/1988/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/snap/core18/1988/lib64/ld-linux-x86-64.so.2
/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/usr/lib64/ld-linux-x86-64.so.2
/usr/share/man/man8/ld-linux.8.gz
/usr/share/man/man8/ld-linux.so.8.gz
Once you have located the dynamic linker utility, you can use it to manually load a program and its libraries (it will run the program as well)
Example:
On Ubuntu distribution using ls
command to list the contents of ~/Music directory.
$ /usr/lib64/ld-linux-x86-64.so.2 /usr/bin/ls ~/Music
config THM
You find that I have config and THM files in my ~/Music directory
Managing the Library Cache
Library cache is a catalog of library directories and all the various libraries contained within them. The system reads this cache file to quickly find needed libraries when it is loading programs. This makes it much faster for loading libraries than searching through all the possible directory locations for a particular required library file.
When new libraries or library directories are added to the system, this library cache file must be updated. Thus, ldconfig
must be run every time configuration files are added or updated.
ldconfig
has the following useful options:
-v
,--verbose
, Display the library version numbers, the name of each directory, and the links that are created:
$ sudo ldconfig -v
/usr/local/lib:
/lib/x86_64-linux-gnu:
libsndio.so.7.0 -> libsndio.so.7.0
libcups.so.2 -> libcups.so.2
libx264.so.155 -> libx264.so.155
libdv.so.4 -> libdv.so.4.0.3
libbd_part.so.2 -> libbd_part.so.2.0.0
libspice-client-gtk-3.0.so.5 -> libspice-client-gtk-3.0.so.5.0.0
In the example above, we see how libsndio.so.7.0
is linked to the actual shared object file libsndio.so.7.0
2. -p
, --print-cache
, Print the lists of directories and candidate libraries stored in the current cache:
$ sudo ldconfig -p
1005 libs found in cache `/etc/ld.so.cache'
libzvbi.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libzvbi.so.0
libzvbi-chains.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libzvbi-chains.so.0
libzstd.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libzstd.so.1
libzip.so.5 (libc6,x86-64) => /lib/x86_64-linux-gnu/libzip.so.5
libz.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libz.so.1
libyelp.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libyelp.so.0
libyaml-0.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libyaml-0.so.2
libyajl.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libyajl.so.2
libx265.so.179 (libc6,x86-64) => /lib/x86_64-linux-gnu/libx265.so.179
Now we can see how the cache uses the fully qualified soname (shared object name) of the links:
$ sudo ldconfig -p |grep libfuse
libfuse.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libfuse.so.2
Let’s now long list /lib/x86_64-linux-gnu/libfuse.so.2
, we will find the reference to the actual shared object file libfuse.so.2.9.9
which is stored in the same directory:
$ ls -l /lib/x86_64-linux-gnu/libfuse.so.2
lrwxrwxrwx 1 root root 16 Sep 1 2020 /lib/x86_64-linux-gnu/libfuse.so.2 -> libfuse.so.2.9.9
We can add new paths for shared libraries temporarily using LD_LIBRARY_PATH
i.e to add /usr/local/mynewlib
to the library path in the current shell session, use:
$ LD_LIBRARY_PATH=/usr/local/mynewlib
Now let’s check the new added library:
$ echo $LD_LIBRARY_PATH
/usr/local/mynewlib
To add /usr/local/mynewlib
permanently to the library path in the current shell session and have it exported to all child processes spawned from that shell, use:
export LD_LIBRARY_PATH=/usr/local/mynewlib
To remove the LD_LIBRARY_PATH
environment variable, use:
unset LD_LIBRARY_PATH
Searching Dependencies of a Particular Executable
To look up the shared libraries required by a specific program, use the ldd
command followed by the absolute path to the program. The output shows the path of the shared library file as well as the hexadecimal memory address at which it is loaded:
$ ldd /usr/bin/ssh
linux-vdso.so.1 (0x00007ffffe1c5000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fef16f5e000)
libcrypto.so.1.1 => /lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007fef16c88000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fef16c82000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fef16c66000)
libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007fef16c4a000)
libgssapi_krb5.so.2 => /lib/x86_64-linux-gnu/libgssapi_krb5.so.2 (0x00007fef16bfd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fef16a09000)
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007fef16979000)
/lib64/ld-linux-x86-64.so.2 (0x00007fef17065000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fef16956000)
libkrb5.so.3 => /lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007fef16879000)
libk5crypto.so.3 => /lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007fef16848000)
libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007fef16841000)
libkrb5support.so.0 => /lib/x86_64-linux-gnu/libkrb5support.so.0 (0x00007fef16830000)
libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007fef16829000)
We also use ldd
to search for the dependencies of a shared object:
$ ldd /lib/x86_64-linux-gnu/libkrb5support.so.0
linux-vdso.so.1 (0x00007ffd2b3e0000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f77ce49a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f77ce2a8000)
/lib64/ld-linux-x86-64.so.2 (0x00007f77ce4c5000)
With the -u
(or --unused
) option ldd
prints the unused direct dependencies (if they exist).
$ ldd -u /usr/bin/ssh
The reason for unused dependencies is related to the options used by the linker when building the binary. Although the program does not need an unused library, it was still linked and labelled as NEEDED
in the information about the object file. You can investigate this using commands such as readelf
or objdump
.
Note: Sometimes a library is dependent on another library. So when you are troubleshooting a missing library file, you may need to use the ldd
command on the libraries listed for the application in order to get to the root of the problem.
Recommended Linux Books to read:
- Best Linux Books for Beginners & Experts
- Best Linux Kernel Programming Books
- Best Linux Bash Scripting Books
- Top RHCSA / RHCE Certification Study Books
- Best Top Rated CompTIA A+ Certification Books
- Best LPIC-1 and LPIC-2 certification study books
Conclusion
This is the the of our guide on how to Manage Shared Libraries on Linux, I hope this guide has been helpful.
Here is a list of other articles you can also check: