为什么链接库的顺序有时会导致 GCC 出错? [英] Why does the order in which libraries are linked sometimes cause errors in GCC?

查看:14
本文介绍了为什么链接库的顺序有时会导致 GCC 出错?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么链接库的顺序有时会导致 GCC 出错?

Why does the order in which libraries are linked sometimes cause errors in GCC?

推荐答案

(查看这个答案的历史以获得更详细的文本,但我现在认为读者更容易看到真正的命令行).

以下所有命令共享的公共文件

Common files shared by all below commands

$ cat a.cpp
extern int a;
int main() {
  return a;
}

$ cat b.cpp
extern int b;
int a = b;

$ cat d.cpp
int b;

链接到静态库

$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o

$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order

链接器从左到右搜索,并在搜索过程中记录未解析的符号.如果一个库解析了符号,它会使用该库的目标文件来解析符号(在这种情况下,b.o 来自 libb.a).

The linker searches from left to right, and notes unresolved symbols as it goes. If a library resolves the symbol, it takes the object files of that library to resolve the symbol (b.o out of libb.a in this case).

静态库相互依赖的工作方式相同——首先需要符号的库,然后是解析符号的库.

Dependencies of static libraries against each other work the same - the library that needs symbols must be first, then the library that resolves the symbol.

如果一个静态库依赖于另一个库,但另一个库又依赖于前一个库,则存在循环.您可以通过 -(-) 封闭循环依赖库来解决此问题,例如 -( -la -lb -)(您可能需要转义括号,例如 -(-)).然后,链接器会多次搜索这些包含的库,以确保解决循环依赖关系.或者,您可以多次指定库,因此每个库都在另一个之前:-la -lb -la.

If a static library depends on another library, but the other library again depends on the former library, there is a cycle. You can resolve this by enclosing the cyclically dependent libraries by -( and -), such as -( -la -lb -) (you may need to escape the parens, such as -( and -)). The linker then searches those enclosed lib multiple times to ensure cycling dependencies are resolved. Alternatively, you can specify the libraries multiple times, so each is before one another: -la -lb -la.

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!

$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order

这里也一样——库必须遵循程序的目标文件.与静态库相比,这里的不同之处在于您无需关心库之间的依赖关系,因为动态库自己会整理它们的依赖关系.

It's the same here - the libraries must follow the object files of the program. The difference here compared with static libraries is that you need not care about the dependencies of the libraries against each other, because dynamic libraries sort out their dependencies themselves.

一些最近的发行版显然默认使用 --as-needed 链接器标志,它强制程序的目标文件位于动态库之前.如果传递了该标志,则链接器将不会链接到可执行文件实际不需要的库(并且它会从左到右检测到这一点).我最近的archlinux发行版默认不使用这个标志,所以它没有因为没有遵循正确的顺序而报错.

Some recent distributions apparently default to using the --as-needed linker flag, which enforces that the program's object files come before the dynamic libraries. If that flag is passed, the linker will not link to libraries that are not actually needed by the executable (and it detects this from left to right). My recent archlinux distribution doesn't use this flag by default, so it didn't give an error for not following the correct order.

创建前者时省略b.sod.so的依赖是不正确的.您将需要在链接 a 时指定库,但 a 并不真正需要整数 b 本身,所以它不应该必须关心 b 自己的依赖关系.

It is not correct to omit the dependency of b.so against d.so when creating the former. You will be required to specify the library when linking a then, but a doesn't really need the integer b itself, so it should not be made to care about b's own dependencies.

如果您错过指定 libb.so

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)

$ g++ -L. -lb a.cpp # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above
$ g++ a.cpp -L. -lb # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right"

如果您现在查看二进制文件有哪些依赖项,您会注意到二进制文件本身也依赖于 libd,而不仅仅是 libb.如果以后 libb 依赖于另一个库,则需要重新链接二进制文件,如果你这样做的话.如果其他人在运行时使用 dlopen 加载 libb(想想动态加载插件),调用也会失败.所以 正确" 也应该是 wrong.

If you now look into what dependencies the binary has, you note the binary itself depends also on libd, not just libb as it should. The binary will need to be relinked if libb later depends on another library, if you do it this way. And if someone else loads libb using dlopen at runtime (think of loading plugins dynamically), the call will fail as well. So the "right" really should be a wrong as well.

这篇关于为什么链接库的顺序有时会导致 GCC 出错?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆