0

What is the meaning of -l (lowercase "L") flags passed to gcc/g++? And where can I find documentation or tutorials on it?


I've tried searching man gcc and man ld for -l, but that has thousands of matches.

Example of a -l flag:

in this:

gcc -Wall -Wextra -Werror -O3 -std=c17 hello_world_extra_basic.c -o bin/a -lm && bin/a

-lm says to include the math library (static .a or dynamic .so?--I don't know) so you can use functions like sin() from math.h.

See:

  1. https://en.cppreference.com/w/c/numeric/math
  2. https://stackoverflow.com/a/12165016/4561887

But I need more detail than that:

  1. What does calling -lgtest or -lm really do? I can clearly manually pass the -I include directories, and .a static prebuilt files myself, for instance, like this from my answer here:

    # to manually build "googletest/googletest/samples/sample1_unittest.cc"
    time ( \
        time g++ -Wall -Wextra -Werror -O3 -std=c++17 -pthread \
        -I"googletest/googletest/include" -I"googletest/googlemock/include" \
        googletest/googletest/samples/sample1_unittest.cc \
        googletest/googletest/samples/sample1.cc \
        bin/libgtest.a bin/libgtest_main.a \
        -o bin/a \
        && time bin/a \
    )
    

    What does -lgtest do instead, and what has to be in-place for this to work?

  2. Why -l? Is that part of what must be present in the name? Does "l" mean something like 'l'inker? Do these flags go to the compiler or the linker?

  3. Why -lpthread vs -pthread? I've seen both before and don't understand the difference.

  4. Are -l includes linking to static .a libraries, or to runtime .so libraries? Where do these libraries exist in your filesystem?

  5. How does this relate to the output of sudo ldconfig -v which I see here?

  6. Can you add your own -l flags? How?

Update: searching ld --help shows this, so l must stand for 'l'ibrary, but is that static or dynamic?:

-l LIBNAME, --library LIBNAME  
                            Search for library LIBNAME
halfer
  • 19,824
  • 17
  • 99
  • 186
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265

2 Answers2

1

I got it figured out well enough to feel comfortable posting an answer. I figured out almost all of the following through extensive trial and error as I wrote my answer here.

For full details, see the "Going further" section at the end of my answer here: How to set up googleTest as a shared library on Linux: "Going further: general information about libraries; debugging; gcc/g++ compiler flags; etc."

Here are some of the salient points:

  1. As I figured out in the bottom of my question, -l presumably means 'l'ibrary. These flags apparently get passed straight through gcc/g++ to the ld linker. See ld --help. The flag -lmylibraryname tells the linker to look for a file named libmylibraryname.a (if a static .a archive library), or a similar name prefixed with lib if a dynamic .so shared object libary. If such a library is found, generally in /usr/lib (usually for system libraries), or /usr/local/lib (usually for user-installed libraries), then the linking is successful.

  2. Header files are also automatically searched for in /usr/include and /usr/local/include.

  3. Based on the naming above, -lm means there must be a file named libm.a, for instance, probably in /usr/lib somewhere. Sure enough, find /usr/lib -path "*libm.*" finds the following:

    $ find /usr/lib -path "*libm.*"
    /usr/lib/x86_64-linux-gnu/libm.so
    /usr/lib/x86_64-linux-gnu/libm.a
    /usr/lib/x86_64-linux-gnu/libm.so.6
    /usr/lib/i386-linux-gnu/libm.so.6
    
  4. -lgtest works because a file named libgtest.a (following that same naming conventino described above) exists at /usr/local/lib/libgtest.a, now that I've followed my own instructions at the link above.

  5. Regarding -lpthread vs -pthread, here are my own notes from my answer above:

    1. A google search for g++ "-lpthread" vs "-pthread" reveals this answer: Difference between -pthread and -lpthread while compiling, which says that the difference between -lpthread and -pthread is historical, so on today's gcc/g++ and clang compilers, you should always just use -pthread to bring in POSIX threads.

      The -lpthread library is now an empty binary apparently and doesn't do anything except satisfy ancient requirements where that library must still be included in some places. But, -pthread handles that all for you, so just use -pthread alone and be done!

  6. Are -l includes linking to static .a libraries, or to runtime .so libraries? Where do these libraries exist in your filesystem?

    Answer: either.

    They are usually found in /usr/lib (system-installed libraries) or /usr/local/lib (user-installed libraries), and their file names must begin with lib.

  7. sudo ldconfig -v shows dynamic libraries only, which are loaded and available for run-time linking now (I think).

  8. Can you add your own -l flags? How?

    Yes! First, build .c/.cpp files into .o files using gcc or g++, then use ar to convert the output .o files into archive .a static library files. Then, copy your .a files into /usr/local/lib via sudo cp -i -t /usr/local/lib lib/libgtest.a lib/libgtest_main.a lib/libgmock.a lib/libgmock_main.a, or similar. For full details on building the .o and .a files manually, see my answer here: How do I build and use googletest (gtest) and googlemock (gmock) with gcc/g++ or clang?.

I think that covers it.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • But.. why didn't you check documentation? https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Link-Options.html#Link-Options and `man gcc` `exists at /usr/local/lib/` See also `/etc/ld.so.conf` and `man ld` and `man ls.so` `sudo ldconfig -v shows dynamic libraries only` See `man ldconfig`. `First, build .c/.cpp files into .o files using gcc or g++, then use ar` Consider using a build system, like CMake, to hide all that complexity and for portability. – KamilCuk Mar 13 '23 at 08:43
0

What is the meaning of -l (lowercase "L") flags passed to gcc/g++?

To link with a library.

And where can I find documentation or tutorials on it?

Locally in man gcc, online at https://gcc.gnu.org/onlinedocs . No idea about tutorials.

What does calling -lgtest or -lm really do?

From https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Link-Options.html#Link-Options :

-llibrary -l library

Search the library named library when linking. (The second alternative with the library as a separate argument is only for POSIX compliance and is not recommended.)

The -l option is passed directly to the linker by GCC. Refer to your linker documentation for exact details. The general description below applies to the GNU linker.

The linker searches a standard list of directories for the library. The directories searched include several standard system directories plus any that you specify with -L.

Static libraries are archives of object files, and have file names like liblibrary.a. Some targets also support shared libraries, which typically have names like liblibrary.so. If both static and shared libraries are found, the linker gives preference to linking with the shared library unless the -static option is used.

It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, ‘foo.o -lz bar.o’ searches library ‘z’ after file foo.o but before bar.o. If bar.o refers to functions in ‘z’, those functions may not be loaded.

Why -l? Is that part of what must be present in the name? Does "l" mean something like 'l'inker?

Shortcut from the word "l"ibrary.

Do these flags go to the compiler or the linker?

Both.

Compiler like means two things. Compiler literally is a translator which translates one language to another. But we call "GCC compiler" what really is "GCC Compiler Collection" - a set of many programs used to compile. GCC compiler includes preprocessor (cpp), compiler (cc1) and linker (ld). Linker is part of the compiler (toolchain). See for example gcc -print-prog-name=cc1.

Why -lpthread vs -pthread?

Difference between -pthread and -lpthread while compiling . And as you found out on newest systems, libpthread.so is empty. Still, for portability, at least for some time prefer to use -pthread.

Are -l includes linking to static .a libraries, or to runtime .so libraries?

Both. .so is preferred over .a, unless -static flag is given, in which case .a is preferred over .so.

Where do these libraries exist in your filesystem?

Note: shared libraries are like needed twice. First, by linker ld as part of the compiler (but really Do shared libraries (.so) files need to present (or specified) at link time?) and then by the ld.so dynamic linker/loader when executing the library. These are different programs and both have different implementations - there are for example GNU ld and ld.gold, there are ld.so from musl and glibc projects.

The linker uses the following search paths to locate required shared libraries:

  1. Any directories specified by -rpath-link options.

  2. Any directories specified by -rpath options. The difference between -rpath and -rpath-link is that directories specified by -rpath

    options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time. Searching -rpath in this way is only supported by native linkers and cross linkers which have been configured with the --with-sysroot option.

  3. On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the environment variable "LD_RUN_PATH".

  4. On SunOS, if the -rpath option was not used, search any directories specified using -L options.

  5. For a native linker, search the contents of the environment variable "LD_LIBRARY_PATH".

  6. For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH" entries exist.

  7. For a linker for a Linux system, if the file /etc/ld.so.conf exists, the list of directories found in that file. Note: the path to this file is prefixed with the "sysroot" value, if that is defined, and then any "prefix" string if the linker was configured with the --prefix= option.

  8. For a native linker on a FreeBSD system, any directories specified by the "_PATH_ELF_HINTS" macro defined in the elf-hints.h header file.

  9. Any directories specified by a "SEARCH_DIR" command in a linker script given on the command line, including scripts specified by -T (but not -dT).

  10. The default directories, normally /lib and /usr/lib.

  11. Any directories specified by a plugin LDPT_SET_EXTRA_LIBRARY_PATH

  12. Any directories specified by a "SEARCH_DIR" command in a default linker script.

From man ld.so:

If a shared object dependency does not contain a slash, then it is searched for in the following order:

(1) Using the directories specified in the DT_RPATH dynamic section attribute of the binary if present and DT_RUNPATH attribute does not exist. Use of DT_RPATH is deprecated.

(2) Using the environment variable LD_LIBRARY_PATH, unless the executable is being run in secure-execution mode (see below), in which case this variable is ignored.

(3) Using the directories specified in the DT_RUNPATH dynamic section attribute of the binary if present. Such directories are searched only to find those objects required by DT_NEEDED (direct dependencies) entries and do not apply to those objects' children, which must them‐ selves have their own DT_RUNPATH entries. This is unlike DT_RPATH, which is applied to searches for all children in the dependency tree.

(4) From the cache file /etc/ld.so.cache, which contains a compiled list of candidate shared objects previously found in the augmented library path. If, however, the binary was linked with the -z nodeflib linker option, shared objects in the default paths are skipped. Shared ob‐ jects installed in hardware capability directories (see below) are preferred to other shared objects.

(5) In the default path /lib, and then /usr/lib. (On some 64-bit architectures, the default paths for 64-bit shared objects are /lib64, and then /usr/lib64.) If the binary was linked with the -z nodeflib linker option, this step is skipped.

How does this relate to the output of sudo ldconfig -v which I see here?

ld.so searches the cache created by ldconfig. The output of ldconfig shows the content of that cache. See man ldconfig.

Can you add your own -l flags? How?

You can type -lanything. You can also create a shared library or a static library named libanything.so and add it to compiler linker search paths.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111