我正在开发一个需要两个第三方库( libfoo.so 和 libbar.so )的C ++项目。我的操作系统是Linux。
libfoo.so 动态链接到libpng14.so.14(1.4.8)(编辑1)
libbar.so 似乎静态链接到一个unknwon版本的libpng libpng 1.2.8 (编辑1)
我说“似乎是”因为:
ldd libbar.so
没有显示png nm -D libbar.so | grep png_read_png
说“004f41b0 T png_read_png”less libbar.so | grep png_read_png
说“4577:004f41b0 738 FUNC GLOBAL DEFAULT 10 png_read_png”当我开始我的程序时,它会中止:
terminate called after throwing an instance of 'char const*'
这是gdb backtrace:
#0 0xb7ffd424 in __kernel_vsyscall ()
#1 0xb5e776a1 in raise () from /lib/libc.so.6
#2 0xb5e78de2 in abort () from /lib/libc.so.6
#3 0xb60a997f in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6
#4 0xb60a78a5 in ?? () from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6
#5 0xb60a78e2 in std::terminate() () from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6
#6 0xb60a7a21 in __cxa_throw () from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6
#7 0xb5abf76d in ?? () from /usr/lib/libfreeimage.so.3
#8 0xb6fb9346 in png_error () from lib/libfsdk.so
#9 0xb6fa2a59 in png_create_read_struct_2 () from lib/libfsdk.so
#10 0xb6fa2b7a in png_create_read_struct () from lib/libfsdk.so
#11 0xb5abfa44 in ?? () from /usr/lib/libfoo.so
#12 0xb5aa766b in FreeImage_LoadFromHandle () from /usr/lib/libfreeimage.so.3
#13 0xb5aa59f6 in FreeImage_LoadFromMemory () from /usr/lib/libfreeimage.so.3
#14 0xb68a94a5 in Foo::Image::load (this=0xb4eff560, input=...)
如您所见,属于libfoo.so的 Foo :: Image :: load 抛出异常
禁用我的代码中使用 libbar.so 并删除链接的部分, Foo :: Image :: load 不会抛出任何异常并且工作正常。
编辑1
png_access_version_number()
png_access_version_number()
返回10208
:版本1.2.8 png_access_version_number()
返回10408
:版本1.4.8 答案 0 :(得分:4)
由于您无法重建任何一个库,并且由于符号冲突而无法允许库驻留在相同的“动态链接器命名空间”中,因此您唯一的选择是 isolate 它们。
您可以使用dlopen("lib*.so", RTLD_LOCAL)
(对于其中一个或两个库)来实现,而不是直接链接到它们。
如果您只需要一些符号,例如,这可能是可行的。 libfoo.so
- 您只需使用dlsym
而不是直接调用函数。
如果您对两个库都有“太多”依赖关系,那么您的另一个解决方案可能是构建一个“内插器”库。假设您要插入libbar.so
,并且需要bar1()
,bar2()
,... bar1000()
。
使用以下内容编写(或使用简单的Perl脚本生成)源文件:
static void *handle;
void *bar1()
{
static void* (*pfn)(void *arg1, void *arg2, void *arg3, ..., argN);
if (pfn == NULL) {
if (handle == NULL)
handle = dlopen("libbar.so", RTLD_LOCAL|RTLD_LAZY);
pfn = dlsym(handle, "bar1");
}
return (*pfn)(arg1, arg2, ..., argN);
}
... repeat for all other libbar functions you depend on
现在编译并将此源链接到libbar_interposer.so
并将您的应用程序链接到它(由于名称重整,这对于C++
不起作用,仅适用于普通 - C
)。 Voila,应用程序没有源更改,并且您仍然已隔离libbar.so
,因此其符号将不会对应用程序的其余部分可见,特别是不会与libpng
中的任何符号冲突。< / p>