Compiling and running applications on Linux involves more than just writing code. Developers must also understand the intricacies of environment variables and command-line tools that dictate where compilers and runtime environments look for necessary files. In this post, we will cover some of them.
Default Search Paths
- Header Files: Compilers like
gcc
andg++
typically look for header files in standard directories such as/usr/include
or/usr/local/include
. These are the places where most system and third-party libraries install their header files. - Libraries: For libraries, the linker (
ld
) searches in directories like/usr/lib
,/usr/local/lib
, and sometimes in more specific directories that depend on the machine’s architecture (like/usr/lib/x86_64-linux-gnu
on 64-bit systems).
Modifying Search Paths with Environment Variables
C_INCLUDE_PATH
and CPLUS_INCLUDE_PATH
These environment variables allow you to add additional directories to the list of directories that the compiler searches for header files. This is especially useful when you have headers in non-standard locations. For example:
export C_INCLUDE_PATH=/home/user/custom_libs/include:$C_INCLUDE_PATH export CPLUS_INCLUDE_PATH=/home/user/custom_libs/include:$CPLUS_INCLUDE_PATH
In these commands, the colon (:
) acts as a delimiter to separate multiple paths. By placing a new path before the existing value of the variable, you ensure that your specified directory is searched before the default directories.
LIBRARY_PATH
This variable works similarly to the include path variables but for library files during the linking stage. If you set LIBRARY_PATH
, you direct the linker to look in additional directories:
export LIBRARY_PATH=/home/user/custom_libs/lib:$LIBRARY_PATH
LD_LIBRARY_PATH
Unlike LIBRARY_PATH
, LD_LIBRARY_PATH
modifies the runtime search path for libraries. It tells the dynamic linker where to look for dynamic libraries. By setting
, you can add additional directories to the search path of the linker. This is particularly useful during development or when using multiple versions of a library, as it avoids the need to permanently install libraries into global directories or alter the system’s library configuration. Setting LD_LIBRARY_PATH
LD_LIBRARY_PATH
can resolve runtime errors related to missing libraries:
export LD_LIBRARY_PATH=/home/user/custom_libs/lib:$LD_LIBRARY_PATH
What to do when you get the *.so: cannot open shared object file: No such file or directory error.
You can always use ldd
to check the dynamic libraries that a program needs to run, showing both the expected locations of these libraries and where they are actually found. If a library cannot be found, ldd
output will indicate this with “not found.” Here’s a clearer example:
ldd /usr/bin/grep linux-vdso.so.1 => (0x00007ffeefbff000) libpcre.so.1 => /lib/x86_64-linux-gnu/libpcre.so.1 (0x00007f2d482a0000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2d47edf000) /lib64/ld-linux-x86-64.so.2 (0x00007f2d48555000) libdl.so.2 => not found
When ldd
indicates that a library is missing, you can use find
to search for it. It’s a powerful command that can scour the entire filesystem or specific directories:
find / -type f -name "libdl.so.2" 2>/dev/null
This command searches for libdl.so.2
starting from the root directory, suppressing error messages to keep the output clean.
Conclusion
Understanding where Linux systems typically look for libraries and headers and knowing how to alter these paths through environment variables are crucial skills for developers. By mastering these variables and tools like ldd
and find
, you can handle compilation and runtime issues more effectively, ensuring smoother development and deployment of your applications.