【发布时间】:2017-10-15 23:06:38
【问题描述】:
注意:请耐心等待,因为这很复杂。它也是为 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 来编译共享库以及将公共库方法的可见性设置为隐藏以尝试限制其访问,但是这两个选项都不起作用。我们还尝试修改公共库方法的一些签名,但我们可以更改的数量有限。
【问题讨论】:
-
如果您希望 CommonStaticLibrary 中的 API 位于每个共享库的内部,请查看visibility 上的 GCC wiki。默认的 Windows 和 Linux 构建系统之间的一大区别是,在 Linux 上,所有内容都默认导出,因此每个库之间的符号冲突。
-
@TavianBarnes,谢谢,我们确实尝试过。我使用 Cmake CMAKE_CXX_VISIBILITY_PRESET 设置为“hidden”,并将“-fvisibility=hidden”显式添加到编译器标志中。两者都没有明显的效果。
标签: c++ linux gcc shared-libraries ld