2011-06-30 90 views
40

我用兩個不同的共享庫鏈接。這兩個庫定義了一些共享名稱但具有不同實現的符號。我不能讓每個庫都使用自己的實現。將兩個共享庫鏈接到一些相同的符號

例如,兩個庫都定義了一個全局函數bar(),它們都在內部調用。圖書館從foo1()調用它,圖書館二從foo2()調用它。

Lib1.so:

T bar 
T foo1()  // calls bar() 

Lib2.so:

T bar 
T foo2()  // calls bar() 

如果我對Lib1.so鏈接到我的應用程序,然後從Lib2.so的Lib1.so落實酒吧甚至被稱爲當致電foo2()。另一方面,如果我將我的應用程序鏈接到Lib2.so然後是Lib1.so,那麼bar總是從Lib2.so中調用。

有沒有辦法讓圖書館總是比其他圖書館更喜歡自己的實現?

回答

40

有幾種方法來解決這個問題:

  • -Bsymbolic-Bsymbolic-functions給鏈接器。這具有全局影響:每個對可以解析爲庫中符號的全局符號(-Bsymbolic-functions的函數類型)的引用都解析爲該符號。藉此,您將失去使用LD_PRELOAD將內部庫調用置於這些符號的能力。 這些符號仍然導出,所以它們可以從庫外引用。

  • 使用版本腳本標識符號的當地圖書館,例如使用類似於:{local: bar;};並將--version-script=versionfile傳遞給鏈接器。 符號是不是已輸出。

  • 與approppiate 能見度GCC info page for visibility),這將是馬克符號要麼隱藏的內部,或保護保護知名度符號導出爲.protected隱藏符號不導出,並內部符號不導出,你妥協不是他們在圖書館外通過函數調用,即使是間接的指針。

您可以檢查哪些符號與objdump -T出口。

+0

嗨,你能告訴我,這是否也適用於鐺? –

3

您將不得不創建兩個'包裝'共享庫,一個用於每個現有的庫。每一個都應該建立一個--dynamic-list,它只列出幾個定義API的非衝突符號。您還需要-Bsymbolic來避免任何全局組合。

使用合適的選項通過dlopen訪問生成的庫也可能不那麼緊張。

+0

非常感謝!只是-Bsymbolic選項(使用-Wl選項傳遞給鏈接器)爲兩個共享庫鏈接解決了我的問題。 – drewag

0

解決此問題的另一種方法是使用宏來更改名稱空間。

先決條件

  • 所有元素(函數,類,全局變量,...)是在一個命名空間。
  • 該庫不會嚴重依賴頭中的宏。

解決方案

  • 當編譯庫,定義宏命名空間名稱來定義它不同的東西。例如,如果命名空間是LibNS,則使用-DLibNS=LibNSv1作爲一種情況,使用-DLibNS=LibNSv2作爲另一種情況。
  • 在代碼中使用庫時,根據您當前的情況定義宏;

    #define LibNS LibNSv1 
    #include "my_lib.h" 
    #undef LibNS 
    

原因,而不是使用其他的解決方案

  • 當問題庫中的頭文件使用(至少部分地)(例如模板,內聯,這... );當你將它們包含在可執行文件的代碼中時,解析器不知道是否應該從Lib1.so或Lib2.so調用這些函數。您的編譯器對其他解決方案的支持很差/不支持(我們的intel/amd 32/64位CPU不應該出現這種情況,但Google搜索似乎發現其他一些平臺可能存在問題)。

潛在的問題

  • 這可能是有問題的可執行文件的一個CPP文件中使用這兩種版本; #include "my_lib.h"可能使用宏來防止多重包含和定義它們以避免這可能會導致很多不同的問題(庫作者可能會在未來更改宏名稱,頭文件定義一些其他宏等)。

注意