2010-05-10 48 views
4

在我的項目中,存在來自第三方的對靜態庫(從現在開始稱爲libsomething)的依賴關係。最近,libsomething已成爲另一個版本。我的任務是爲我的軟件提供對舊版和新版的支持。 libsomething在任何給定時間僅在運行時使用一個版本,但在程序運行之間應配置哪個版本。在動態庫中包裝不同版本的靜態庫

我在WinXP上使用MSVC2005,第二個目標是準備切換到Linux和GCC。

因爲libsomething的兩個版本都使用相同的符號,所以將它們鏈接到我的可執行文件中是不可能的,因爲這兩個版本的符號都會在鏈接時發生衝突。雖然我可以創建兩個可執行文件(一個與舊版本鏈接,另一個使用新版本),但我無法實現在最終部署環境中調用哪個可執行文件(遺留原因)的決定。

我想出了爲libsomething的每個版本創建一個動態庫包裝的想法,並根據一些配置文件在運行時鏈接它們。對於MSCV來說,這意味着要走上使用LoadLibrary(),GetProcAddress()等的道路,而在Linux上我將不得不使用dlopen()dlsym()

據我所知,使用libtool(即libtldl)正在包裝這個平臺依賴項以使用共享庫。這是一條適合的路徑嗎?有更好的(或者至少是不同的)方式嗎? libtldl的替代方案是否以開源方式存在?

回答

0

它已經有幾年了,但我想提出另一種完整性的解決方案。您可以生成所有必要功能的簡單存根(而不是手動dlopendlsym),並在第一次調用時(或在程序啓動時)確定需要哪個庫版本,加載它並解析地址。

你可以寫一個腳本,專門爲您量身打造的項目,或者使用Implib.so工具:

# This will generate mylib.so.init.c and mylib.so.tramp.S 
# which implement stubs. These need to be linked to your 
# executable. 
$ gen-implib.py mylib.so 

Implib.so是僅支持Linux的ATM,但應該是很容易適應的Windows。

+0

是的,這幾乎是我在2010年完成的事情。所以,我想這使得它成爲可接受的解決方案。 :-) – fawick 2017-12-07 19:23:47

2

我知道你說你不能使用兩個可執行文件,因爲決定執行哪個可執行文件,但是不能在可執行文件之間來回exec,具體取決於在配置中選擇哪個版本?

+0

你說得對,在這種情況下,這種方法確實產生了一個解決方案。雖然我更感興趣通過鏈接來完成它。但是你的想法是聰明的開箱即用的思想! – fawick 2010-05-10 18:23:47

2

在Linux上,您可以更容易地鏈接到共享庫並使用符號鏈接來更正版本 - IMO比使用dlopen() + dlsym()更容易。

新版本和舊版本的庫因此您將創建共享庫:

g++ -shared -o libshared.so.1.1 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.old -Wl,-no-whole-archive

g++ -shared -o libshared.so.1.2 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.new -Wl,-no-whole-archive

創建符號鏈接:

ln -s libshared.so.1.1 libshared.so.1 
ln -s libshared.so.1 libshared.so 

建設您的應用程序,將其鏈接到舊版本的庫。我想這兩個版本都是二進制兼容的(ABI沒有損壞),但是新版本可能會有一些新的符號。

g++ -o myapp myapp.cpp -L. -lshared

由於共享庫的SONAMElibshared.so.1您的應用程序依賴於它,並會在路徑搜索libshared.so.1/etc/ld.so.confLD_LIBRARY_PATH

在你運行你的應用程序,您可以設置libshared.so.1符號鏈接指向libshared.so.1.2libshared.so.1.1


關於這裏使用的連接選項一點信息:

--whole歸檔
對於--whole存檔選項後,在命令行中提到的每個存檔,包括在每一個目標文件 鏈接中的存檔,而不是在存檔中搜索所需的目標文件。這通常用於將歸檔文件轉換爲共享庫,強制每個對象都包含在生成的共享庫中。該選項可能會多次使用。
從gcc使用這個選項時有兩點需要注意:首先,gcc不知道這個選項,所以你必須使用-Wl,-whole-archive。 其次,不要忘記在歸檔列表後面使用-Wl,-no-whole-archive,因爲gcc會將自己的歸檔列表添加到您的 鏈接中,並且您可能不希望此標誌也影響這些歸檔。

-soname = name
創建ELF共享對象時,請將內部DT_SONAME字段設置爲指定的名稱。當可執行文件與具有DT_SONAME字段的共享對象鏈接時,那麼當可執行文件運行時,動態鏈接程序將嘗試加載由DT_SONAME字段指定的共享對象 ,而不是使用賦予鏈接程序的文件名。

+0

很好的答案,謝謝。不幸的是,如你所說,這隻適用於Linux。因此,當我最終移植到Linux時,它是值得回來的,但在那天之前不適用。 – fawick 2010-05-12 13:24:13