注意:请耐心等待,因为这令人费解。这也是为Windows设计的遗留软件,我正尝试移植以与C ++标准/ Linux兼容。我只给出一些高级示例,这些示例可以重现该问题,因为我将无法给出生产代码的示例。请不要问我们为什么这样做,只知道我们这样做,我必须处理。
我们有许多共享库使用的静态库。例如,FirstSharedLib.so和SecondSharedLib.so都依赖于CommonStaticLibrary.lib。
现在,CommonStaticLibrary.lib声明了打算由共享库实现的方法。例如,GetSharedLibraryName();
因此,FirstSharedLib项目通过返回“ FirstSharedLib”来实现CommonStaticLibrary的GetSharedLibraryName,同样,SecondSharedLib通过返回“ SecondSharedLib”来实现它。
这在Windows中可以按预期工作,例如,当FirstSharedLib调用GetSharedLibraryName()时;它接收到“ FirstSharedLib”字符串,然后在SecondSharedLib调用GetSharedLibraryName()时接收该字符串;它接收到“ SecondSharedLib”字符串。
但是,在Linux(gcc / ld)中进行编译和运行时,动态链接程序将加载第一个共享库,查看CommonStaticLibrary :: GetSharedLibraryName()的实现,然后将其用于调用GetSharedLibraryName()的所有其他共享库,而不考虑实际实现是什么。
因此,在这种情况下,如果FirstSharedLib在调用GetSharedLibraryName()时首先被加载;它接收到“ FirstSharedLib”字符串,但是在加载SecondSharedLib时,它还将接收“ FirstSharedLib”。
或者,如果先加载SecondSharedLib,则对GetSharedLibraryName()的所有调用均返回“ SecondSharedLib”。
是否有一个链接器选项来预链接静态库的共享元素,以便在SecondSharedLib调用GetSharedLibraryName()时,它始终调用该项目创建的实现?
请注意,当我们加载共享库时,我可以看到指向内存中唯一实现的指针,只是只要任何其他库调用它,运行时就会始终调用第一个加载的实例。
我们使用CMake作为构建系统,但是除了我将使用CMake命令传递链接器和/或编译器标志的事实外,这应该没有太大关系。
我试图使用-fPIC来编译共享库以及将公共库方法的可见性设置为隐藏以试图限制其访问,但是没有一个选项起作用。我们还尝试修改了一些公共库方法的签名,但是我们在更改它的数量上受到限制。
最佳答案
在加载动态库的方法中,我们传递了RTLD_GLOBAL,它显然覆盖了编译时传递的隐藏属性。
我们删除了RTLD_GLOBAL标志(将其替换为RTLD_LOCAL 0x0),现在这些库将静态库方法保留在发起共享库的本地。我们还可以删除标志以将属性设置为隐藏。
旧代码:
int flag = RTLD_NOW | RTLD_GLOBAL;
void* library = dlopen( libraryName, flag );
新代码:
int flag = RTLD_NOW | RTLD_LOCAL;
void* library = dlopen( libraryName, flag );