共享库libbar.so静态链接到libfoo.a,程序链接到libbar.so和libfoo.so,会发生什么?

时间:2015-09-18 00:55:16

标签: c++ linker global-variables shared-libraries static-libraries

(希望这不会太复杂......)

我已经构建了包含静态(libfoo)和共享(libfoo.a)版本的第三方C ++库libfoo.so。目标文件是使用-fPIC创建的。 libfoo有几个用于配置其行为的全局变量,以及依赖于这些全局变量的函数,以简化与变量func1()交互的函数global_a

我已经构建了我与libbar静态链接的C ++共享库libfoo.a。这是在没有--whole-archive选项的情况下完成的。因此,我认为libbar.so包含了libfoo.a所需的所有符号和定义。该库调用来自libfoo的函数,它使用全局变量来控制行为。在这种情况下,我们假设它调用函数func1()

最后,我有一个C ++客户端程序baz,可动态链接到libfoo.solibbar.so。此客户端还使用libfoo中的相同函数/全局变量。它会修改global_a并调用func1()

通常,在这种情况下,客户端baz的行为是什么?这种配置是我应该避免的,还是可以的?如果libfoo.alibfoo.so是不同的版本,会发生什么?

对于全局变量,我有点期待libbar.so中的代码会使用自己的副本,baz中的任何更改都会修改libfoo.so中的副本,但是&# 39;不是我所看到的。当baz修改global_a时,效果会在libbar.so中看到。我可以告诉客户baz没有任何其他异常行为。

我还尝试将bazlibfoo.a相关联,并看到相同(显然是正确的)行为。

Valgrind在任何一种情况下都没有显示任何错误。

1 个答案:

答案 0 :(得分:1)

  

一般情况下,客户端baz在这种情况下的行为是什么?

通常,UNIX / ELF系统上共享库的行为旨在模仿归档库的行为。

特别是,如果您的二进制baz链接libfoo.solibbar.so,两者都 export global_a,那么第一个定义胜。也就是说,global_abazlibfoo.solibbar.so的所有引用都将绑定到链接顺序中找到的第一个实例(此处可能是libfoo.so)。

可以通过隐藏符号来修改此行为。 -fvisibility-hidden__attribute__((visibility("hidden")))或链接描述文件。

您可以使用

查看每个库导出的内容
nm -AD libfoo.so libbar.so | grep global_a

(此命令仅显示导出的符号)。

  

对于全局变量,我有点期待libbar.so中的代码会使用自己的副本

期望不正确。

  

这种配置是我应该避免的,还是可以的?

这是您通常应该避免的,因为例如更新libbar.so而不重新链接libfoo.so可能会产生不一致。假设global_a的类型在以后的修订版中从int更改为double。突然之间有一个简单的陈述:

global_a = 0.0;
libbar.so内的

现在可能会损坏global_alibfoo.so后面的无关变量(global_a内的libfoo.so仍为4字节{{1} },但现在写入8字节int。)

  

Valgrind在任何一种情况下都没有显示错误。

Valgrind在检查全局变量时特别弱,几乎从不抱怨它们。您应养成使用double检查程序的习惯。