Paths that you need to know for compiling

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 and g++ 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 LD_LIBRARY_PATH, 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 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.

Author