2010-07-12 46 views
26

Tôi có một ứng dụng liên kết tĩnh với phiên bản X của thư viện, libfoo, từ nhà cung cấp bên thứ ba, VENDOR1. Nó cũng liên kết với một thư viện động (được chia sẻ), libbar, từ một nhà cung cấp bên thứ ba khác, VENDOR2, liên kết tĩnh phiên bản Y của libfoo từ VENDOR1.Liên kết với nhiều phiên bản của thư viện

Vì vậy, libbar.so chứa phiên bản Y của libfoo.a và tệp thi hành của tôi có chứa phiên bản X của libfoo.a libbar chỉ sử dụng libfoo nội bộ và không có đối tượng libfoo nào được chuyển từ ứng dụng của tôi sang libbar.

Không có lỗi tại thời gian xây dựng nhưng khi chạy lỗi ứng dụng seg. Lý do dường như là phiên bản X sử dụng các cấu trúc có kích thước khác nhau mà chúng phiên bản Y và trình liên kết thời gian chạy dường như được trộn lẫn mà được sử dụng theo đó.

Cả VENDOR1 & VENDOR2 là nguồn đóng nên tôi không thể xây dựng lại chúng.

Có cách nào để xây dựng/liên kết ứng dụng của tôi sao cho nó luôn phân giải thành phiên bản X và libbar luôn giải quyết phiên bản Y và cả hai không bao giờ kết hợp?

+0

Bạn có thể đặt ứng dụng của mình liên kết động với VENDOR1 không? –

+0

Không theo bất kỳ cách nào là ngôn ngữ trung lập. Điều này rất cụ thể đối với trình liên kết trình biên dịch và hệ điều hành cách chúng hoạt động cùng nhau. Cách dễ nhất là gửi e-mail cho cả người bán hàng và xem cách họ giải quyết vấn đề này. –

+0

Suy nghĩ hiện tại của chúng tôi là, trên Linux ít nhất, để sử dụng dlopen() trên libbar.so với cờ RTLD_DEEPBIND. Một khả năng khác là tách riêng các ứng dụng sử dụng libfoo.a thành thư viện được chia sẻ, libbaz.so kết thúc tốt đẹp việc sử dụng libfoo.a, sau đó có ứng dụng dlopen libbaz.so và libbar.so với RTLD_LOCAL mà chúng tôi nghĩ có thể giữ tất cả các ký hiệu trùng lặp bên trong. Điều này có thể làm việc cho Linux nhưng chúng tôi cần nó để làm việc trên Solaris, AIX & HPUX là tốt. – YerBlues

Trả lời

11

Cảm ơn tất cả các câu trả lời. Tôi có một giải pháp dường như đang hoạt động. Đây là vấn đề chi tiết với một ví dụ.

Trong main.c ta có:

#include <stdio.h> 

extern int foo(); 

int bar() 
{ 
    printf("bar in main.c called\n"); 
    return 0; 
} 

int main() 
{ 
    printf("result from foo is %d\n", foo()); 
    printf("result from bar is %d\n", bar()); 
} 

Trong foo.c ta có:

extern int bar(); 

int foo() 
{ 
    int x = bar(); 
    return x; 
} 

Trong bar.c ta có:

#include <stdio.h> 

int bar() 
{ 
    printf("bar in bar.c called\n"); 
    return 2; 
} 

Compile bar.c và foo.c:

$ gcc -fPIC -c bar.c 
$ gcc -fPIC -c foo.c 

Thêm bar.o thư viện tĩnh:

$ ar r libbar.a bar.o 

Bây giờ tạo ra một thư viện chia sẻ sử dụng foo.o và liên kết với tĩnh libbar.a

$ gcc -shared -o libfoo.so foo.o -L. -lbar 

Compile main.c và liên kết với thư viện chia sẻ libfoo.so

$ gcc -o main main.c -L. -lfoo 

Đặt LD_LIBRARY_PATH để tìm libfoo.và chạy chính:

$ setenv LD_LIBRARY_PATH `pwd` 
$ ./main 
bar in main.c called 
result from foo is 0 
bar in main.c called 
result from bar is 0 

Lưu ý rằng phiên bản của thanh trong main.c được gọi, chứ không phải phiên bản được liên kết trong thư viện được chia sẻ.

Trong main2.c ta có:

#include <stdio.h> 
#include <dlfcn.h> 


int bar() 
{ 
    printf("bar in main2.c called\n"); 
    return 0; 
} 

int main() 
{ 
    int x; 
    int (*foo)(); 
    void *handle = dlopen("libfoo.so", RTLD_GLOBAL|RTLD_LAZY); 
    foo = dlsym(handle, "foo"); 
    printf("result from foo is %d\n", foo()); 
    printf("result from bar is %d\n", bar()); 
} 

biên dịch và chạy main2.c (chú ý chúng tôi không cần phải liên kết rõ ràng với libfoo.so):

$ gcc -o main2 main2.c -ldl 
$ ./main2 
bar in bar.c called 
result from foo is 2 
bar in main2.c called 
result from bar is 0 

Bây giờ foo trong chia sẻ thanh cuộc gọi thư viện trong thư viện được chia sẻ và thanh cuộc gọi chính trong main.c

Tôi không nghĩ hành vi này trực quan và sử dụng dlopen/dlsym nhiều hơn, nhưng nó giải quyết được vấn đề của tôi.

Cảm ơn một lần nữa vì đã nhận xét.

1

Rất tiếc, không. Sự hiểu biết của tôi về cách mà Linux (và có thể là hầu hết * nixes) là điều đó là không thể. Chỉ có 'giải pháp' cho vấn đề của bạn mà tôi có thể nghĩ đến, là nếu bạn tạo một ứng dụng proxy, cho thấy những gì bạn cần từ libbar dưới dạng một số IPC. Sau đó, bạn có thể làm cho proxy đó tải phiên bản chính xác bằng cách sử dụng LD_LIBRARY_PATH hoặc một cái gì đó tương tự.

+0

"và có thể là hầu hết * nix" - ngoại trừ AIX. Trên AIX đó là thực sự có thể và hành vi liên kết mặc định không chính xác những gì câu hỏi yêu cầu. – Dummy00001

+0

OS X cũng xử lý điều này một cách duyên dáng. Mỗi .so/.dylib có bảng liên kết/tham chiếu của riêng nó. Tôi nói * nhất * chính xác vì tôi biết không phải tất cả. Dù sao, Linux không làm điều này, AFAIK. – Gianni

5

Hãy thử một liên kết một phần để bạn có tệp đối tượng "partial.o" với libbar và libfoo-Y. Sử dụng objcopy với "--localize-symbols" để tạo các biểu tượng một phần.o từ địa chỉ libfoo-Y. Bạn sẽ có thể tạo ra bằng cách chạy nm trên libfoo-Y và xoa bóp đầu ra. Sau đó lấy partial.o đã sửa đổi và liên kết nó với ứng dụng của bạn.

Tôi đã thực hiện điều gì đó tương tự với gcc toolchain trên vxWorks nơi lib động không phải là một biến chứng nhưng hai phiên bản của cùng một lib cần thiết để liên kết sạch thành ứng dụng nguyên khối.

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