链接具有不兼容依赖项的库
我正在开发一个需要两个第三方库(libfoo.so 和 libbar.so)的 C++ 项目。我的操作系统是Linux。
libfoo.so 动态链接到 libpng14.so.14 (1.4.8) (EDIT 1)
libbar.so 似乎是静态链接到 libpng 的未知版本 libpng 1.2.8 (EDIT 1)
我说“似乎是”,因为:
ldd libbar.so
不显示任何关于 pngnm -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 回溯:
#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=...)
如您所见,异常在 Foo::Image:: 中抛出load 属于 libfoo.so
禁用我的代码中使用 libbar.so 的部分并删除指向它的链接, Foo::Image::load 不会抛出任何异常并且工作正常。
所以我猜这可能是由于符号表中的一些歧义造成的。我该如何修复它?
编辑 1
png_access_version_number()
- 链接 libbar.so 后,
png_access_version_number()
返回10208
:版本 1.2.8 - 不带libbar.so 链接,
png_access_version_number()
返回10408
:版本 1.4.8
I'm working on a C++ project that needs two third party libraries (libfoo.so and libbar.so). My operating system is Linux.
libfoo.so is dynamically linked to libpng14.so.14 (1.4.8) (EDIT 1)
libbar.so seems to be statically linked to an unknwon version of libpng libpng 1.2.8 (EDIT 1)
I say "seems to be" because:
ldd libbar.so
doesn't show nothing about pngnm -D libbar.so | grep png_read_png
says "004f41b0 T png_read_png"less libbar.so | grep png_read_png
says "4577: 004f41b0 738 FUNC GLOBAL DEFAULT 10 png_read_png"
When i start my program, it abort:
terminate called after throwing an instance of 'char const*'
This is 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=...)
As you can see, exception is thrown in Foo::Image::load which belong to libfoo.so
Disabling the part of my code that uses libbar.so and removing linking to it, Foo::Image::load doesn't throw any exception and works fine.
So I guess it can be due to some ambiguity in symbol table. How can I fix it?
EDIT 1
png_access_version_number()
- With libbar.so linked,
png_access_version_number()
return10208
: version 1.2.8 - Without libbar.so linked,
png_access_version_number()
return10408
: version 1.4.8
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于您无法重建任何一个库,并且由于符号冲突而不允许这些库驻留在同一“动态链接器命名空间”中,因此您唯一的选择就是隔离它们。
您可以通过使用
dlopen("lib*.so", RTLD_LOCAL)
(对于其中一个或两个库)来实现此目的,而不是直接链接到它们。如果您只需要来自例如 libfoo.so 的一些符号,这可能是可行的 - 您可以简单地使用 dlsym 而不是直接调用函数。
如果您对这两个库有“太多”依赖项,则另一个解决方案可能是构建一个“插入器”库。假设您想要插入
libbar.so
,并且需要bar1()
、bar2()
、...bar1000( )
来自它。编写(或使用简单的 Perl 脚本生成)一个如下所示的源文件:
现在编译此源并将其链接到
libbar_interposer.so
中,然后将您的应用程序链接到它(这不适用于C++
由于名称修改,仅适用于纯C
)。瞧,应用程序的源代码没有更改,并且您仍然具有隔离的libbar.so
,因此它的符号对应用程序的其余部分不可见,特别是不会与中的任何符号发生冲突>libpng
。Since you can't rebuild either of the libraries, and since the libraries can not be allowed to reside in the same "dynamic linker namespace" due to conflicting symbols, your only choice is to isolate them.
You can achieve that by using
dlopen("lib*.so", RTLD_LOCAL)
(for either or both of the libraries), instead of linking to them directly.This could be workable if you only need a few symbols from e.g.
libfoo.so
-- you can simply usedlsym
instead of calling the functions directly.If you have "too many" dependencies on both libraries, your other solution may be to build an "interposer" library. Let's say you want to interpose
libbar.so
, and you needbar1()
,bar2()
, ...bar1000()
from it.Write (or generate with a simple Perl script) a source file that looks like this:
Now compile and link this source into
libbar_interposer.so
and link your application against it (this will not work forC++
due to name mangling, only for plain-C
). Voila, no source changes to the application, and you still have isolatedlibbar.so
so its symbols will not be visible to the rest of the application, and in particular will not conflict with any symbols inlibpng
.