2011-12-16 68 views
9

我正在研究需要兩個第三方庫(libfoo.solibbar.so)的C++項目。我的操作系統是Linux。具有不兼容依賴關係的鏈接庫

libfoo.so動態鏈接到libpng14.so.14(1.4.8)(EDIT 1)

libbar.so似乎靜態鏈接到 的libpng的unknwon版本 的libpng 1.2.8 (EDIT 1)

我說 「似乎」,是因爲:

  • ldd libbar.so沒什麼不顯示,有關PNG
  • nm -D libbar.so | grep png_read_png說: 「004f41b0牛逼png_read_png」
  • less libbar.so | grep png_read_png說: 「4577:004f41b0 738 FUNC全局默認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=...) 

正如你所看到的,異常拋出美孚::圖像::負載屬於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
+2

您必須使用`nm -D`來查看共享庫的dynsyms。只有`nm`適用於調試符號,在大多數發行版中都會被剝離。 – 2011-12-16 14:22:01

+0

@jørgensen,謝謝! – 2011-12-16 14:28:10

回答

4

由於您無法重建任一庫,並且由於符號衝突導致庫無法駐留在相同的「動態鏈接程序名稱空間」中,因此您唯一的選擇是隔離區它們。

您可以通過使用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中的任何符號衝突。