注意:请耐心等待,因为这是令人费解的。它也是为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来编译共享库,并将公共库方法的可见性设置为隐藏以试图限制其访问,但这两个选项都没有用。我们还试图修改Common库方法的一些签名,但是我们可以更改它的数量有限。
答案 0 :(得分:1)
在我们加载动态库的方法中,我们传递了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 );