how to specify alternate linker command when linking with 'cc'

The -B option allows you to specify an alternate search path for executables, libraries, include files & data files that the compiler will use. This works for some versions of gcc [1] and for clang (currently undocumented - in man pages of at least clang 3.7 & 3.8):

cc -B/usr/local/bin foo.c -o foo

Note that this will cause cc to search for other tools (e.g., the assembler) in the path specified by -B. So supposing you have a different version of binutils installed in /usr/local/bin, if you only want to use that linker (rather than /usr/local/bin/as, et. al.), you could do something like this:

mkdir /tmp/usemyld
ln -s /usr/local/bin/ld /tmp/usemyld
cc -B/tmp/usemyld foo.c -o foo

-B has its own set of rules that allow you to override different files that the gcc compiler tries to use (programs, libraries, include files, data files). This is documented as far back as at least gcc 2.95 - read the gcc man / info pages. I don't know how compatible the behavior of -B is for clang. As mentioned, it's not currently documented in the clang man page. But it worked well enough to allow me to select an alternate linker as shown above.

gcc also supports calling a script/program as specified by -wrapper. clang does not (currently). You could also use that and point at a wrapper script that alters what program the compiler is calling. I don't know if collect2 heeds the -wrapper option (and for gcc, collect2 is what calls the linker when compiling c/c++ programs at least).

[1] The linker search order documented in the gcc info page for collect2 says that it will search first for "a hard coded linker file name if GCC was configured with the '--with-ld' option"). So if your gcc was not configured with '--with-ld', then it will eventually search in the path specified by -B (if it doesn't find real-ld first). If your gcc was configured with --with-ld, then the -B option will not help you specify an alternate linker of your choosing.


Certain linkers are easy to use - just gcc -fuse-ld=lld main.c. This appears to have been added somewhere in gcc version 4. -fuse-ld also works with clang 10.0.1.

Supported linkers are listed on https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html

-fuse-ld=bfd

Use the bfd linker instead of the default linker.

-fuse-ld=gold

Use the gold linker instead of the default linker.

-fuse-ld=lld

Use the LLVM lld linker instead of the default linker.

Hopefully this helps people coming from searches, as OP long ago had their question answered.


GCC uses internally spec files (to decide how the gcc program behaves, in particular how it is linking and with what linker). You can configure or change that with -specs= so have your own spec file and use it. Or use the -T option (of gcc which explicitly passes it to ld) to give a linker script.

The default spec is obtained with gcc -dumpspecs

Also, by strace(1)-ing some gcc command, you'll find out that it tries to access e.g. /usr/lib/gcc/x86_64-linux-gnu/specs; so put your own spec file there.

Those spec files are textual, so you should be able to write your own.

But I am not sure it is a good idea.

BTW, /usr/bin/cc is on Linux distribution a symlink (on Debian: /usr/bin/cc -> /etc/alternatives/cc -> /usr/bin/gcc), either to some gcc or to some clang. AFAIK, cc (and c99) is specified in POSIX (but of course, nothing is told about its relation to ld)

Tags:

C++

C

Linker