(希望这不会太复杂......)
我已经构建了包含静态(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.so
和libbar.so
。此客户端还使用libfoo
中的相同函数/全局变量。它会修改global_a
并调用func1()
。
通常,在这种情况下,客户端baz
的行为是什么?这种配置是我应该避免的,还是可以的?如果libfoo.a
和libfoo.so
是不同的版本,会发生什么?
对于全局变量,我有点期待libbar.so
中的代码会使用自己的副本,baz
中的任何更改都会修改libfoo.so
中的副本,但是&# 39;不是我所看到的。当baz
修改global_a
时,效果会在libbar.so
中看到。我可以告诉客户baz
没有任何其他异常行为。
我还尝试将baz
与libfoo.a
相关联,并看到相同(显然是正确的)行为。
Valgrind在任何一种情况下都没有显示任何错误。
答案 0 :(得分:1)
一般情况下,客户端baz在这种情况下的行为是什么?
通常,UNIX / ELF系统上共享库的行为旨在模仿归档库的行为。
特别是,如果您的二进制baz
链接libfoo.so
和libbar.so
,两者都 export global_a
,那么第一个定义胜。也就是说,global_a
,baz
和libfoo.so
对libbar.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_a
内libfoo.so
后面的无关变量(global_a
内的libfoo.so
仍为4字节{{1} },但现在写入8字节int
。)
Valgrind在任何一种情况下都没有显示错误。
Valgrind在检查全局变量时特别弱,几乎从不抱怨它们。您应养成使用double
检查程序的习惯。