Placement of '-L' Option in Gcc

position of gcc -l option

The linker simply resolve external references in the order they are presented on the command line.

Taking the example in your quote, foo.o -lz bar.o: If foo.o uses functions in the z library then those are resolved when the linker loads the z library. However it doesn't really cache those entries, and once the external references have been resolved using the z library, the linker forgets about them. Now when bar.o comes along and attempts to use functions from the z library, those will not be resolved since the linker will not read the z library again.

Placement of `-l' option in gcc

From the manual,

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.

This means it is very interesting that linking the library first works on gcc 4.1.2. This might have to do with the default libraries linked to by the compiler. I know on some installations I don't need to explicitly link to pthreads.

On further reflection, I think the issue is with the flag --as-needed, which may be on by default in your gcc 4.6 system. See this link for some discussion.

Why does the order of '-l' option in gcc matter?

Because that's how the linking algorithm used by GNU linker works (a least when it comes to linking static libraries). The linker is a single pass linker and it does not revisit libraries once they have been seen.

A library is a collection (an archive) of object files. When you add a library using the -l option, the linker does not unconditionally take all object files from the library. It only takes those object files that are currently needed, i.e. files that resolve some currently unresolved (pending) symbols. After that, the linker completely forgets about that library.

The list of pending symbols is continuously maintained by the linker as the linker processes input object files, one after another from left to right. As it processes each object file, some symbols get resolved and removed from the list, other newly discovered unresolved symbols get added to the list.

So, if you included some library by using -l, the linker uses that library to resolve as many currently pending symbols as it can, and then completely forgets about that library. If it later suddenly discovers that it now needs some additional object file(s) from that library, the linker will not "return" to that library to retrieve those additional object files. It is already too late.

For this reason, it is always a good idea to use -l option late in the linker's command line, so that by the time the linker gets to that -l it can reliably determine which object files it needs and which it doesn't need. Placing the -l option as the very first parameter to the linker generally makes no sense at all: at the very beginning the list of pending symbols is empty (or, more precisely, consists of single symbol main), meaning that the linker will not take anything from the library at all.

In your case, your object file example.o contains references to symbols ud_init, ud_set_input_file etc. The linker should receive that object file first. It will add these symbols to the list of pending symbols. After that you can use -l option to add the your library: -ludis86. The linker will search your library and take everything from it that resolves those pending symbols.

If you place the -ludis86 option first in the command line, the linker will effectively ignore your library, since at the beginning it does not know that it will need ud_init, ud_set_input_file etc. Later, when processing example.o it will discover these symbols and add them to the pending symbol list. But these symbols will remain unresolved to the end, since -ludis86 was already processed (and effectively ignored).

Sometimes, when two (or more) libraries refer to each other in circular fashion, one might even need to use the -l option twice with the same library, to give linker two chances to retrieve the necessary object files from that library.

gcc l option order?

When you use

gcc -g -O2 -Wall -I/usr/local/include -lprotobuf-c -o addressbooktest addressbooktest.c MyAddressBook.pb-c.c

the linker (which is a separate program which is invoked by the gcc front-end program) runs, it will find the library protobuf-c but since no one (yet) uses any functions from it, it will be ignored.

what is implied by using the -L in gcc flag in gcc post-ceded by a dot

The . (dot) refers to the current directory. Therefore these options are specifying that the current directory should be searched for any required header files (-I.) and any required libraries (-L.).

From the GCC manual:

-Idir
Add the directory dir to the head of the list of directories to be searched for header files.

-Ldir
Add directory dir to the list of directories to be searched for -l.

-l library
Search the library named library when linking.

From the POSIX specification:

The special filename dot shall refer to the directory specified by its predecessor.

Does the order of -l and -L options in the GNU linker matter?

Yes, the order of -L options matters - just like -l and -I options.

From man ld

-Lsearchdir
--library-path=searchdir

Add path searchdir to the list of paths that ld will search for archive libraries and ld control scripts. You may use this option any number of times. The directories are searched in the order in which they are specified on the command line. Directories specified on the command line are searched before the default directories. All -L options apply to all -l options, regardless of the order in which the options appear.

GCC documentations and more specifically Linking Options will be useful for you

Edit
Sorry, indeed I missed to check the link you've given. "man ld" can just be written in the console.

Edit2
I made a simple test putting -l before -L options and it shows no difference comparing to -L before -l

So answering your second question, this

gcc -lm hello.c -Lx

is equal to this

gcc -Lx -lm hello.c

libm is searched first in directory x/ in both tests.

Note though that putting -l<lib> before source files is a bad practice, that may lead to undefined references when linking. This is the correct way

gcc hello.c -Lx -lm 

How to specify preference of library path?

Add the path to where your new library is to LD_LIBRARY_PATH (it has slightly different name on Mac ...)

Your solution should work with using the -L/my/dir -lfoo options, at runtime use LD_LIBRARY_PATH to point to the location of your library.

Careful with using LD_LIBRARY_PATH - in short (from link):

..implications..:

Security: Remember that the directories specified in LD_LIBRARY_PATH get searched before(!) the standard locations? In that
way, a nasty person could get your application to load a version of a
shared library that contains malicious code! That’s one reason why
setuid/setgid executables do neglect that variable!

Performance: The link loader has to search all the directories specified, until it finds the directory where the shared library
resides – for ALL shared libraries the application is linked against!
This means a lot of system calls to open(), that will fail with
“ENOENT (No such file or directory)”! If the path contains many
directories, the number of failed calls will increase linearly, and
you can tell that from the start-up time of the application. If some
(or all) of the directories are in an NFS environment, the start-up
time of your applications can really get long – and it can slow down
the whole system!

Inconsistency: This is the most common problem. LD_LIBRARY_PATH forces an application to load a shared library it wasn’t linked
against, and that is quite likely not compatible with the original
version. This can either be very obvious, i.e. the application
crashes, or it can lead to wrong results, if the picked up library not
quite does what the original version would have done. Especially the
latter is sometimes hard to debug.

OR

Use the rpath option via gcc to linker - runtime library search path, will be used
instead of looking in standard dir (gcc option):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

This is good for a temporary solution. Linker first searches the LD_LIBRARY_PATH for libraries before looking into standard directories.

If you don't want to permanently update LD_LIBRARY_PATH you can do it on the fly on command line:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

You can check what libraries linker knows about using (example):

/sbin/ldconfig -p | grep libpthread
libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

And you can check which library your application is using:

ldd foo
linux-gate.so.1 => (0xffffe000)
libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
librt.so.1 => /lib/librt.so.1 (0xb7e65000)
libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
/lib/ld-linux.so.2 (0xb7fc7000)
libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
libz.so.1 => /lib/libz.so.1 (0xb7c18000)

How to link using GCC without -l nor hardcoding path for a library that does not follow the libNAME.so naming convention?

There is the ":" prefix that allows you to give different names to your libraries.
If you use

g++ -o build/bin/myapp -l:_mylib.so other_source_files

should search your path for the _mylib.so.

Linking libssl and libcrypto in GCC

It turns out it was something stupid. In the linker step, I was using gcc -Wall -g -lssl -lcrypto -o program program.o. I needed to move the library links to after the object file I was linking, and put libssl before libcrypto:

gcc -Wall -g -o program program.o -lssl -lcrypto


Related Topics



Leave a reply



Submit