2010-07-12 36 views
26

我有一個應用程序與來自第三方供應商VENDOR1的庫libfoo的版本X靜態鏈接。它還與來自另一個第三方供應商VENDOR2的動態(共享)庫libbar鏈接,該靜態鏈接來自VENDOR1的libfoo版本Y.與多個版本的庫鏈接

因此,libbar.so包含版本Y的libfoo.a和我的可執行文件包含libfoo.a的版本X libbar只在內部使用libfoo,並且沒有從我的應用程序傳遞給libbar的libfoo對象。

構建時沒有錯誤,但在運行時應用程序段出現故障。原因似乎是,版本X使用的結構具有不同的大小,它們的版本爲Y,並且運行時鏈接程序似乎正在混合,哪些會被哪些使用。

兩個供應商1 &供應商2是閉源的,所以我不能重建它們。

是否有建立/鏈接我的應用程序,使得它始終解析版本X和libbar的送花兒給人解析到版本Y和兩個從未混合的方法嗎?

+0

你可以讓你的應用動態鏈接到VENDOR1嗎? – 2010-07-12 23:31:32

+0

不以任何方式與語言無關。這對於編譯器鏈接器和操作系統來說非常具體,它們是如何一起工作的。最簡單的方法是通過電子郵件向供應商和他們如何解決這個問題。 – 2010-07-12 23:31:43

+0

我們目前的想法是,至少在linux上,使用libbar.so上的dlopen()和RTLD_DEEPBIND標誌。另一種可能性是將libfoo.a的應用程序分離到共享庫中,libbaz.so將libfoo.a封裝起來,然後將應用程序dlopen libbaz.so和libbar.so與RTLD_LOCAL分離,我們認爲這可能會保留所有重複的符號在內部。這可能適用於Linux,但我們需要它,因此也適用於Solaris,AIX和HPUX。 – YerBlues 2010-07-13 00:05:42

回答

11

感謝您的所有回覆。我有一個似乎正在工作的解決方案。 下面是一個例子的詳細問題。

main.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()); 
} 

在foo.c的有:

extern int bar(); 

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

在bar.c,我們有:

#include <stdio.h> 

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

編譯bar.c和foo.c的:

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

添加文件bar.o到靜態庫:

$ ar r libbar.a bar.o 

現在創建使用文件foo.o並鏈接與靜態共享庫搜索libbar.a

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

編譯main.c中與共享庫鏈接libfoo.so

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

設置LD_LIBRARY_PATH以查找libfoo。所以並運行主:

$ 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 

請注意,在main.c中欄的版本叫做,沒有連接到共享庫的版本。

在main2.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()); 
} 

編譯和運行main2.c(注意我們不需要明確地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 

現在foo的共享共享庫中的庫調用欄和main.c中的主要調用欄。我不認爲這種行爲是直觀的,使用dlopen/dlsym更多的工作,但它確實解決了我的問題。

再次感謝您的評論。

1

對不起沒有。我對Linux(也可能是大多數* nixes)的方式的理解是不可能的。我能想到的唯一解決問題的方法是創建一個代理應用程序,它以一些IPC的形式公開您需要從libbar獲得的內容。然後,您可以使用LD_LIBRARY_PATH或類似的東西使該代理加載正確的版本。

+0

「可能大多數* nixes」 - 除AIX外。在AIX上,這實際上是可行的,而默認的鏈接器行爲恰好是問題所在。 – Dummy00001 2010-07-13 00:07:55

+0

OS X也可以優雅地處理這個問題。每個.so/.dylib都有自己的鏈接表/參考。我說*多數*正是因爲我知道這不是全部。無論如何,Linux不會這樣做,AFAIK。 – Gianni 2010-07-13 00:29:38

5

嘗試的部分鏈接,讓你有一個目標文件「partial.o」與libbar的和libfoo的-Y。將objcopy與「--localize-symbols」一起使用,以使libfoo-Y local.part中的符號成爲partial.o。您應該能夠通過在libfoo-Y上運行nm並按摩輸出來生成。然後採取修改partial.o並將其鏈接到您的應用程序。

我已經做了VxWorks的gcc工具類似的東西在那裏動態庫不是一個複雜而乾淨地連接成一個整體的應用程序所需要的相同的lib的兩個版本。