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

时间:2016-11-07 17:22:30

标签: c++ c linker

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

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

我不是在寻找涉及单独运行各种编译步骤的方法(例如,预处理,编译,汇编,链接)。

例如,我希望这样的事情可以完成这项工作:

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

但这对gcc或clang不起作用。当然,如果你有一个首先构建一个目标文件的makefile,然后调用$ {LD}来链接(例如,env LD=/usr/local/bin/ld make

,它会工作。

更新(有一个可能的动机):使用与默认链接器不同的链接器轻松测试。例如,能够做到这一点会很高兴:

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

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

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相同):< / p>

/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)。文档说它看起来是第一个的“硬编码链接器文件名”。如果该文档是正确的,为了强制它不使用该链接器(即欺骗它),您必须重命名默认链接器(例如,sudo mv /usr/bin/ld /usr/bin/ld.tmp-disable)。

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

4 个答案:

答案 0 :(得分:4)

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

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

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

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 man / info页面。我不知道-B对于clang的行为有多兼容。如上所述,它目前没有记录在clang手册页中。但它足以让我选择如上所示的备用链接器。

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

[1] gcc collect2信息页面中记录的链接器搜索顺序表示,如果GCC配置了&,它将首先搜索&#34;硬编码链接器文件名。 #39; - 与-LD&#39;选项&#34)。因此,如果您的gcc未配置&#39; - with-ld&#39;,那么它最终会搜索-B指定的路径(如果它找不到real-ld第一)。如果您的gcc 配置了--with-ld,那么-B选项将无法帮助您指定您选择的备用链接器。

答案 1 :(得分:2)

GCC在内部使用spec files(以决定gcc程序的行为方式,特别是它如何链接以及与哪个链接器相关联)。您可以配置或更改with -specs=,以便拥有自己的spec文件并使用它。或者使用-T optiongcc 显式将其传递给ld)来提供链接描述文件。

使用gcc -dumpspecs

获取默认规范

此外,通过strace(1) - 一些gcc命令,您会发现它尝试访问例如/usr/lib/gcc/x86_64-linux-gnu/specs /usr/bin/cc;所以把你自己的spec文件放在那里。

那些spec文件是文本的,所以你应该能够自己编写。

但我不确定这是个好主意。

BTW,/usr/bin/cc -> /etc/alternatives/cc -> /usr/bin/gcc在Linux发行版上是一个符号链接(在Debian上:gcc),可以是某些clang,也可以是某些cc。 AFAIK,ld(和c99)在POSIX中指定(但当然,没有告诉它与{{1}}的关系)

答案 2 :(得分:0)

我想使用lld(LLVM链接器),因为我更喜欢它的错误消息。这(以及其他一些特殊情况)很容易-仅gcc -fuse-ld=lld main.c-fuse-ld标志在我的系统上也适用于clang。

来自https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html

  

-fuse-ld = bfd

     

使用bfd链接器代替默认链接器。

     

-fuse-ld =金

     

使用黄金链接器代替默认链接器。

     

-fuse-ld = lld

     

使用LLVM lld链接器代替默认链接器。

希望这对搜索人员有所帮助,因为OP很早以前就回答了他们的问题。

答案 3 :(得分:0)

将包含备用链接器ld的目录放置到PATH环境变量的前面。

例如,如果ld中有备用~/local/binexport PATH=~/local/bin:$PATH将导致cc使用~/local/bin/ld