Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
198 views
in Technique[技术] by (71.8m points)

c++ - how to specify alternate linker command when linking with 'cc'

When you use cc(1) to link a program, it will invoke a default linker command. For instance, your version of the compiler may have been built to use /usr/bin/ld by default on a unix-like platform.

Is there a way to specify a different linker command that cc(1) (or c++(1)) should use (e.g., /usr/local/bin/ld instead of /usr/bin/ld)? I'm interested mostly in gcc and clang.

I'm not looking for methods that involve running the various compilation steps separately (e.g., pre-process, compile, assemble, link).

For example, I was hoping something like this might do the job:

env LD=/usr/local/bin/ld cc foo.c -o foo

But that doesn't work for gcc or clang. It would work, of course, if you had a makefile that built an object file first, then invoked ${LD} to link (e.g., env LD=/usr/local/bin/ld make)

Update (with one possible motivation): To easily test with a different linker than the default linker. For example, it would be nice to be able to do this:

cc --linker=/usr/local/bin/ld foo.c -o foo

Instead, you have to do generate the object file, run cc -v to figure out the arguments to ld, manually run the ld you want with those arguments:

cc -c foo.c
cc -v foo.c -o /dev/null

Now look at the linker invocation and manually copy/paste replacing linker and temporary object file. Something like this (example taken from a test on fedora 23) where you replace /usr/libexec/gcc/x86_64-redhat-linux/5.3.1/collect2 with /usr/local/bin/ld (although it's not exactly the same as collect2):

/usr/local/bin/ld -plugin /usr/libexec/gcc/x86_64-redhat-linux/5.3.1/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-redhat-linux/5.3.1/lto-wrapper -plugin-opt=-fresolution=/tmp/jhein/ccM2XKIg.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o c /usr/lib/gcc/x86_64-redhat-linux/5.3.1/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/5.3.1/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/5.3.1/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/5.3.1 -L/usr/lib/gcc/x86_64-redhat-linux/5.3.1/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/5.3.1/../../.. c.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/5.3.1/crtend.o /usr/lib/gcc/x86_64-redhat-linux/5.3.1/../../../../lib64/crtn.o

As you can see, that's not easy. Note there is documentation in the gcc info page about how collect2 looks for a linker program. But according to those docs, the first place it looks is not an environment variable or something you can specify on the command line (e.g., --linker). The docs say it looks first for a "a hard coded linker file name". If that documentation is correct, to coerce it not to use that linker (i.e., trick it), you would have to rename the default linker (e.g., sudo mv /usr/bin/ld /usr/bin/ld.tmp-disable).

Update 2: Using -B seems to work well enough for my needs. See below where I posted an answer. I can't accept my own answer, but I would if I could - it seems to solve the issue well.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...