There are two steps to build a program with gcc: compilation and linking.

gcc is mostly responsible for the compilation, while when linking, it uses linker program (e.g. ld) with some additional flags.

In compilation, gcc only requires header files ( .h  files) to make sure that external function calls have correct parameters matched with the definition.
Then, in linking stage, the linker connects/links all compiled objects and libraries to executable file.

There are two types of libraries: static library ( .a) and dynamic library ( .so, .dynlib, dll). Static libraries are copied directly to the executable file. In opposite, dynamic libraries are not. Dynamic libraries are supposed to be found in the system before the executable file being executed.

So, Where does gcc looking for header files, and dynamic libraries.

Check configuration

In compilation

For c: echo | gcc -x c -E -Wp,-v - >/dev/null
For cpp: echo | gcc -x c++ -e -Wp,-v - >/dev/null

Output from my PC

For C

ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/7/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

For cpp

ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/7"
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/c++/7
 /usr/include/x86_64-linux-gnu/c++/7
 /usr/include/c++/7/backward
 /usr/lib/gcc/x86_64-linux-gnu/7/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

In linking

  • ld's search directories:
ld --verbose | grep SEARCH_DIR | tr -s ' ;' \\012

Output from my PC

SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu")
SEARCH_DIR("=/lib/x86_64-linux-gnu")
SEARCH_DIR("=/usr/lib/x86_64-linux-gnu")
SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64")
SEARCH_DIR("=/usr/local/lib64")
SEARCH_DIR("=/lib64")
SEARCH_DIR("=/usr/lib64")
SEARCH_DIR("=/usr/local/lib")
SEARCH_DIR("=/lib")
SEARCH_DIR("=/usr/lib")
SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64")
SEARCH_DIR("=/usr/x86_64-linux-gnu/lib")
  • gcc wraps some flags when calling ld, thus, directories list is different
gcc -print-search-dirs | sed '/^lib/b 1;d;:1;s,/[^/.][^/]*/\.\./,/,;t 1;s,:[^=]*=,:;,;s,;,;  ,g' | tr \; \\012 | tr : \\012

Output from my PC

libraries

  /usr/lib/gcc/x86_64-linux-gnu/7/
/usr/x86_64-linux-gnu/lib/x86_64-linux-gnu/7/
/usr/x86_64-linux-gnu/lib/x86_64-linux-gnu/
/usr/x86_64-linux-gnu/lib/
/usr/lib/x86_64-linux-gnu/7/
/usr/lib/x86_64-linux-gnu/
/usr/lib/
/lib/x86_64-linux-gnu/7/
/lib/x86_64-linux-gnu/
/lib/
/usr/lib/x86_64-linux-gnu/7/
/usr/lib/x86_64-linux-gnu/
/usr/lib/
/usr/x86_64-linux-gnu/lib/
/usr/lib/
/lib/
/usr/lib/
  • My gcc build detail with gcc --verbose
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.4.0-1ubuntu1~18.04.1' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)

Note: gcc looks for the provided libraries' names from left to right, and stop finding when find out the first library which matches the searched name.

  • You also can show the library search directories list by adding verbose flag -v when linking.
    For example: gcc -v foo.o bar.o -o foo
  • To figure out which libraries are linked with a program and the libraries' full path. Use ldd. For example: ldd foo. Example output from my PC.
	linux-vdso.so.1 (0x00007fff08bf3000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fbc85170000)
	libblas.so.3 => /lib/x86_64-linux-gnu/libblas.so.3 (0x00007fbc85110000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbc84f1f000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fbc852e8000)
	libopenblas.so.0 => /lib/x86_64-linux-gnu/libopenblas.so.0 (0x00007fbc82d3a000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fbc82d17000)
	libgfortran.so.5 => /lib/x86_64-linux-gnu/libgfortran.so.5 (0x00007fbc82a77000)
	libquadmath.so.0 => /lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007fbc82a2b000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fbc82a11000)

How to add a directory as library search directory

Customized library paths, which are added to the compilation/linking, by the following method have higher priority than the default library search directories. In other words, if a library is found in customized directory, it will be selected rather than the library in system default.

Compilation

Method 1: use CPATH (c or c++), C_INCLUDE_PATH (c only), CPLUS_INCLUDE_PATH (c++ only). For example: CPATH=/home/transang/my_libs_headers gcc -c foo.c -o foo.o.

Method 2: use -I<dir_path> to gcc when compiling. For example: gcc -I/home/transang/my_libs_headers -c foo.c -o foo.o.

Linking

Method 1: To add an directory to library linking search directories list, use LD_LIBRARY_PATH environment variable. For example: LD_LIBRARY_PATH=/home/transang/my_libs gcc foo.o bar.o -o foo

Method 2: add flag -L<dir_path> to gcc when linking. For example: gcc -L/home/transang/my_libs foo.o bar.o -o foo.

Note 1: LD_LIBRARY_PATH environment variable's value does not affect the results of ld --verbose and gcc -print-search-dirs commands.
Note 2: LD_LIBRARY_PATH 's value affects result of ldd command. Thus, ldd command is the more reliable way to figure out library path.
Note 3: You also have to provide the LD_LIBRARY_PATH value when running the executable file. For e.g. LD_LIBRARY_PATH=/home/transang/my_libs ./foo.


How to add dynamic library when linking

So far, I have introduced the way to figure out current configuration and modify the configuration to add more directories for library searching.

To link a library add -l<lib_name> flag to the gcc command when linking. If the lib_name does not start with :, gcc will look for a library named lib<lib_name>.so. Otherwise, the file name lib_name will be searched.

For example: with -lfoo, gcc looks for libfoo.so file. With -l:foo.so, gcc looks for foo.so file.