[英]Linking a shared library in executable vs. another shared lib
tl;dr tl; dr
Are there any differences in the way linux loads and links a shared library if the library is linked by an executable or by another shared library? 如果库是通过可执行文件或其他共享库链接的,则linux加载和链接共享库的方式是否有所不同?
Background 背景
Suppose I have a shared library (eg libA.so
) containing a class with a static std::map
and a set of singleton classes. 假设我有一个共享库(例如
libA.so
),其中包含一个带有静态std::map
和一组单例类。 Each singleton class has access to the map and statically adds an instance of itself to the map. 每个单例类都可以访问地图,并将自身的实例静态添加到地图。
There are two scenarios: 有两种情况:
libA.so
) in an executable to read all the registered classes from the global map. libA.so
)从全局映射中读取所有已注册的类。 libA.so
) in another shared library ( libB.so
) and use this new one in an executable. libB.so
)中使用共享库( libA.so
),并在可执行文件中使用这个新库。 In this case libB.so
uses the map from libA.so
to provide some functionality to the executable (like a facade). libB.so
使用libA.so
的映射为可执行文件提供某些功能(例如外观)。 Problem 问题
If I use (ie link) this shared library in an executable (scenario 1), the aforementioned map contains the list of singleton classes, however , if I use this library in another shared library and then use the new one in an executable (scenario 2), the map seems to be empty. 如果我在可执行文件中使用(即链接)此共享库(场景1),则上述映射包含单例类的列表, 但是 ,如果我在另一个共享库中使用此库,然后在可执行文件中使用新的共享库(场景1) 2),地图似乎是空的。
I cannot seem to understand how the linker handles the shared libraries in either of cases. 在这两种情况下,我似乎都无法理解链接器如何处理共享库。
Update 更新资料
As it turned out libB.so
does not link to libA.so
correctly even as explicitly instructed using -lA
flag of g++
. 因为它变成了
libB.so
不链接到libA.so
正确,即使使用的明确指示-lA
的标志g++
。 Even though I cannot see libA.so
linked by libB.so
using ldd
, pmap
or objdump
, I get no runtime errors when using classes of libA.so
. 虽然我不能看到
libA.so
通过链接libB.so
使用ldd
, pmap
或objdump
,我使用的类时,没有得到运行时错误libA.so
。 If I run the same command with clang++
I can see that all required libraries are listed. 如果使用
clang++
运行相同的命令,则可以看到列出了所有必需的库。
Drepper's paper How To Write a Shared Library is a good reference on the subject and should answer your question. Drepper的论文“ 如何编写共享库”是该主题的很好参考,应该回答您的问题。
You should be sure that in the second scenario, the library is linked only once (eg using the exact same path). 您应该确保在第二种情况下,库仅链接一次(例如,使用完全相同的路径)。 See ld-linux(8) and use eg
LD_DEBUG
etc... 参见ld-linux(8)并使用例如
LD_DEBUG
等...
You might also strace
your execution to understand what is going on. 您可能还会
strace
执行以了解发生了什么。
And you should check (with pmap
or using cat /proc/$ThePid/maps
) that the library is loaded only once. 并且您应该检查(使用
pmap
或使用cat /proc/$ThePid/maps
)该库仅加载一次。
I will describe a scenario that could produce the behavior you are seeing. 我将描述一种可能产生您所看到的行为的方案。
Another scenario: 另一种情况:
libB.so
from a global constructor, it may be called before any object has had a chance to register itself. libB.so
中读取映射,则可能在任何对象有机会注册自身之前调用它。 Generally, there is no guaranteed order of execution of global constructors from different translation units, and certainly not from different shared libraries. 通常,不能保证从不同的翻译单元(当然也不能从不同的共享库)执行全局构造函数的顺序。
A solution to the first issue above would be to use a singleton style pattern for your map, so that it is initialized on use rather than through a global constructor. 上面第一个问题的解决方案是为地图使用单例样式模式,以便在使用时进行初始化,而不是通过全局构造函数进行初始化。
TheMap & GlobalMap () {
static TheMap instance;
return instance;
}
A solution to the second issue above would be suppress accessing the global map from global constructors. 上面第二个问题的解决方案是禁止从全局构造函数访问全局地图。 That is, change all global constructors in
libB.so
to be initialize on use rather than initialize in a global constructor. 也就是说,将
libB.so
所有全局构造函数更改为在使用时进行初始化,而不是在全局构造函数中进行初始化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.