与“cc"链接时如何指定备用链接器命令

2022-01-11 00:00:00 c linker c++

当您使用 cc(1) 链接程序时,它将调用默认链接器命令.例如,您的编译器版本可能已构建为在类 unix 平台上默认使用/usr/bin/ld.

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.

有没有办法指定 cc(1)(或 c++(1))应该使用的不同链接器命令(例如,/usr/local/bin/ld 而不是 /usr/bin/ld)?我主要对 gcc 和 clang 感兴趣.

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

但这不适用于 gcc 或 clang.当然,如果您有一个先构建目标文件的 makefile,然后调用 ${LD} 进行链接(例如,env LD=/usr/local/bin/ld make),它会起作用

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

相反,您必须生成目标文件,运行 cc -v 找出 ld 的参数,手动运行 ld 你想要这些论点:

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

现在查看链接器调用并手动复制/粘贴替换链接器和临时目标文件.像这样的东西(示例取自 Fedora 23 上的测试),您将 /usr/libexec/gcc/x86_64-redhat-linux/5.3.1/collect2 替换为 /usr/local/bin/ld(虽然它与 collect2 并不完全相同):

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

如您所见,这并不容易.请注意,gcc 信息页面中有关于 collect2 如何查找链接器程序的文档.但是根据那些文档,它首先看起来不是环境变量或您可以在命令行上指定的东西(例如,--linker).文档说它看起来 first 是硬编码的链接器文件名".如果该文档是正确的,要强制它不使用该链接器(即欺骗它),您必须重命名默认链接器(例如,sudo mv/usr/bin/ld/usr/bin/ld.tmp-禁用).

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).

更新 2:使用 -B 似乎可以很好地满足我的需求.请参阅下面我发布答案的地方.我不能接受自己的答案,但如果可以的话,我会接受――这似乎很好地解决了问题.

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.

推荐答案

-B 选项允许您为可执行文件、库、包含文件和编译器将使用的数据文件.这适用于某些版本的 gcc [1] 和 clang(目前未记录 - 在至少 clang 3.7 和 3.8 的手册页中):

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

请注意,这将导致 cc 在 -B 指定的路径中搜索其他工具(例如,汇编程序).因此,假设您在/usr/local/bin 中安装了不同版本的 binutils,如果您仅想使用该链接器(而不是 /usr/local/bin/as 等),你可以这样做:

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 有自己的一套规则,允许您覆盖 gcc 编译器尝试使用的不同文件(程序、库、包含文件、数据文件).这至少可以追溯到 gcc 2.95 - 阅读 gcc 手册/信息页面.我不知道 -B 的行为与 clang 的兼容性如何.如前所述,它目前没有记录在 clang 手册页中.但它工作得很好,让我可以选择一个备用链接器,如上所示.

-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 还支持调用 -wrapper 指定的脚本/程序.clang 没有(目前).您也可以使用它并指向一个包装脚本,该脚本会改变编译器正在调用的程序.我不知道 collect2 是否注意到 -wrapper 选项(对于 gcccollect2 是调用至少编译 c/c++ 程序时的链接器).

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] collect2gcc 信息页面中记录的链接器搜索顺序表示,如果配置了 GCC,它将首先搜索硬编码的链接器文件名使用--with-ld"选项").所以如果你的gcc没有配置'--with-ld',那么它最终会在-B指定的路径中搜索(如果没有找到real-ld首先).如果您的 gcc 配置了 --with-ld,那么 -B 选项将无法帮助您指定您选择的备用链接器.

[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.

相关文章