2011-12-16 37 views
9

Tôi đang làm việc trên một dự án C++ cần hai thư viện của bên thứ ba (libfoo.solibbar.so). Hệ điều hành của tôi là Linux.Liên kết các thư viện với các phụ thuộc không tương thích

libfoo.so là tự động kết nối với libpng14.so.14 (1.4.8) (EDIT 1)

libbar.so dường như được liên kết tĩnh để một phiên bản unknwon của libpng libpng 1.2.8 (EDIT 1)

tôi nói "có vẻ là" bởi vì:

  • ldd libbar.so không hiển thị gì về png
  • nm -D libbar.so | grep png_read_png nói "004f41b0 T png_read_png"
  • less libbar.so | grep png_read_png nói "4577: 004f41b0 738 FUNC GLOBAL DEFAULT 10 png_read_png"

Khi tôi bắt đầu chương trình của tôi, nó hủy bỏ :

terminate called after throwing an instance of 'char const*' 

Đây là 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=...) 

Như bạn thấy, ngoại lệ được ném vào Foo :: Hình ảnh :: tải thuộc libfoo.so

Vô hiệu hóa các phần của mã của tôi có sử dụng libbar.so và loại bỏ các liên kết đến nó, Foo :: Hình ảnh :: tải không ném bất kỳ ngoại lệ và hoạt động tốt.

Vì vậy, tôi đoán nó có thể là do một số sự mơ hồ trong bảng biểu tượng. Làm thế nào tôi có thể sửa chữa nó?

EDIT 1

png_access_version_number()

  • Với libbar.so liên kết, png_access_version_number() trở 10208: phiên bản 1.2.8
  • Without libbar.so liên kết, png_access_version_number() trở 10408: phiên bản 1.4.8
+2

Bạn phải sử dụng 'nm -D' để xem các dynsym của thư viện được chia sẻ. Chỉ 'nm' là dành cho các biểu tượng gỡ lỗi, được loại bỏ trong hầu hết các bản phân phối. –

+0

@ jørgensen, cảm ơn bạn! –

+0

Tôi đang cố gắng hiểu phiên bản libpng nào được liên kết tĩnh với * libbar.so * –

Trả lời

4

Vì bạn không thể xây dựng lại một trong hai thư viện và vì các thư viện không thể được phép cư trú trong cùng một "không gian tên liên kết động" do các ký hiệu xung đột, lựa chọn duy nhất của bạn là cách ly chúng.

Bạn có thể đạt được điều đó bằng cách sử dụng dlopen("lib*.so", RTLD_LOCAL) (đối với một hoặc cả hai thư viện), thay vì liên kết trực tiếp với chúng.

Điều này có thể hoàn toàn khả thi nếu bạn chỉ cần một vài ký hiệu, ví dụ:libfoo.so - bạn chỉ có thể sử dụng dlsym thay vì gọi trực tiếp các chức năng.

Nếu bạn có "quá nhiều" phụ thuộc vào cả hai thư viện, giải pháp khác của bạn có thể là xây dựng một thư viện "interposer". Giả sử bạn muốn xen kẽ libbar.so và bạn cần bar1(), bar2(), ... bar1000() từ đó.

Write (hoặc tạo ra với một kịch bản Perl đơn giản) một tập tin nguồn mà trông như thế này:

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 

Bây giờ biên dịch và liên kết mã nguồn này vào libbar_interposer.so và liên kết ứng dụng của bạn chống lại nó (điều này sẽ không làm việc cho C++ do tên mangling, chỉ cho đồng bằng- C). Tuy nhiên, không có thay đổi nguồn nào đối với ứng dụng và bạn vẫn bị cách ly libbar.so để biểu tượng của nó sẽ không hiển thị cho phần còn lại của ứng dụng và đặc biệt sẽ không xung đột với bất kỳ ký hiệu nào trong libpng.

+0

Cần lưu ý rằng bạn nên cẩn thận không chuyển các cấu trúc dữ liệu libpng giữa libfoo và libbar nếu bạn làm điều này. Ngoài ra, hãy thử xây dựng lại libbar để liên kết động với libpng nếu có thể. – bdonlan

+0

Cảm ơn bạn! Điều này cho tôi một số hy vọng. Giải pháp của tôi đã tách ra một phần của chương trình bằng cách sử dụng libbar.so và trao đổi dữ liệu với chương trình chính thông qua bộ nhớ chia sẻ. Nhưng giải pháp này có vẻ thanh lịch hơn. –

+0

Tôi đã sử dụng giải pháp của bạn, nhưng với một số thay đổi: viết một số hàm "wrapper" trong thư viện mới "libbar_wrapper.so" và tải nó bằng 'dlopen' và' dlsym'. Tôi cần cả hai cờ 'RTLD_LOCAL | RTLD_LAZY'. Và nó hoạt động! Câu trả lời sử thi! –

Các vấn đề liên quan