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

查看:28
本文介绍了为什么库链接的顺序有时会导致 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

链接器从左到右搜索,并在搜索过程中记录未解析的符号.如果库解析符号,则需要该库的目标文件来解析符号(在这种情况下是 libb.a 中的 b.o).

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(考虑动态加载插件),调用也会失败.所以正确"也应该是一个错误.

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天全站免登陆