传递给链接器的库顺序

Order of libraries passed to linker

在我生命中的某一时刻,传递给 gcc 的库的顺序很重要。您将库列表从最依赖到最不依赖传递给 gcc。例如考虑以下源代码:

testlib.c

include <math.h>

double proxy_sqrt(double x)
{
    return sqrt(x);
}

testlib.h

double proxy_sqrt(double);

使用-testlib.c

#include "testlib.h"

int main(int argc, char* argv[])
{
    proxy_sqrt(36);
    return 0;
}

然后编译 link:

gcc -c -o testlib.o testlib.c
ar rvs testlib.a testlib.o
gcc -o use-testlib use-testlib.c testlib.a -lm

请注意,最后一步使用的是从最依赖到最不相关的顺序。

但是这个(无效的?)订单适用于 SLES12

gcc -o use-testlib use-testlib.c -lm testlib.a 

但在 Ubuntu 14.04 失败....

gcc -o use-testlib use-testlib.c -lm testlib.a
testlib.a(testlib.o): In function `proxy_sqrt':
testlib.c:(.text+0x1b): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status

有人知道为什么吗?

2 个编译器的详细输出显示在下面的 link 处:

sles12

http://pastebin.com/sKe8B7V9

ubuntu14.04

http://pastebin.com/vf8fTaE2

查看链接器 (collect2) 命令与 --as-needed--no-as-needed 选项的区别:

SLES 12

/usr/lib64/gcc/x86_64-suse-linux/4.8/collect2 --build-id --eh-frame-hdr \
    -m elf_x86_64 -dynamic-linker … /tmp/ccgoQd94.o -lm testlib.a -lgcc \
    --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s \
    --no-as-needed /usr/lib64/gcc/x86_64-suse-linux/4.8/crtend.o \
    /usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../lib64/crtn.o

Ubuntu 14

/usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 --sysroot=/ --build-id --eh-frame-hdr \
    -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker … \
    /tmp/cciheQTH.o -lm testlib.a -lgcc --as-needed -lgcc_s \
    --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed \
    /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o \
    /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o

在 Ubuntu 14 的选项开头使用 --as-needed 与 SLES 12 相比改变了事物的行为。据说,这是为了让事情变得更容易。我仍然相信 - 它似乎只是提供了新的代码在移动时中断的方法。

库的分组导致组中的每个库都被重复搜索,直到没有更多的引用被解析。

不分组,每个库按从左到右的顺序只检索一次。

(可以在命令行中重复库名以帮助解决此类问题)

来自 gcc 链接器的手册页:http://linux.die.net/man/1/ld

--开始组档案--结束组

档案应该是档案文件的列表。它们可以是明确的文件名,也可以是 -l 选项。

重复搜索指定的档案,直到没有新的未定义引用被创建。通常,只会按照在命令行中指定的顺序搜索一次存档。如果需要该存档中的符号来解析稍后出现在命令行中的存档中的对象所引用的未定义符号,则链接器将无法解析该引用。通过对档案进行分组,重复搜索它们,直到解决所有可能的引用。

使用此选项会产生显着的性能成本。最好只在两个或多个档案之间存在不可避免的循环引用时才使用它。