
我知道Linux下的共享物件使用“so number”,即共享物件的不同版本被賦予不同的擴展名,例如:
example.so.1
example.so.2
我理解這個想法是擁有兩個不同的文件,以便系統上可以存在兩個版本的庫(而不是 Windows 上的“DLL Hell”)。我想知道這在實踐中是如何運作的?通常,我發現這example.so
實際上是指向最新版本的符號example.so.2
連結.2
。那麼依賴舊版的應用程式如何example.so
正確識別它呢?是否有任何規則規定必須使用哪些數字?或者這只是慣例?與 Windows 中軟體二進位檔案在系統之間傳輸不同,如果系統具有更新版本的共享對象,那麼在從原始程式碼編譯時,它會自動連結到舊版本嗎?
我懷疑這與相關,ldconfig
但我不確定如何。
答案1
二進位檔案本身知道它們依賴哪個版本的共用庫,並專門請求它。您可以使用ldd
來顯示依賴關係;我的ls
是:
$ ldd /bin/ls
linux-gate.so.1 => (0xb784e000)
librt.so.1 => /lib/librt.so.1 (0xb782c000)
libacl.so.1 => /lib/libacl.so.1 (0xb7824000)
libc.so.6 => /lib/libc.so.6 (0xb76dc000)
libpthread.so.0 => /lib/libpthread.so.0 (0xb76c3000)
/lib/ld-linux.so.2 (0xb784f000)
libattr.so.1 => /lib/libattr.so.1 (0xb76bd000)
正如您所看到的,它指向 例如libpthread.so.0
,而不僅僅是libpthread.so
。
之所以使用符號連結是為了連結器。當您想要直接連結時libpthread.so
,您可以給出gcc
標誌-lpthread
,它會自動添加lib
前綴和.so
後綴。您無法告訴它添加後綴.so.0
,因此符號連結指向最新版本的庫以方便添加
答案2
共享庫中的數字是 Linux 中用來識別庫的 API 的約定。通常格式為:
libFOO.so.MAJOR.MINOR
正如您所注意到的,通常有一個從 libFOO.so 到 libFOO.so.MAJOR.MINOR 的符號連結。 ldconfig 負責將此連結更新到最新版本。
當 API 變更(新入口點被刪除或參數或類型變更)時,MAJOR 通常會遞增。 MINOR 通常會在錯誤修復版本或引入新 API 且不破壞現有 API 時增加。
更廣泛的討論可以在這裡找到:剖析共享庫
答案3
共享庫應根據以下方案進行版本控制:
blah.so.X.Y.Z
在哪裡
- X = 向後不相容的 ABI 版本
- Y = 向後相容的 ABI 版本
- Z = 僅內部更改 - ABI 沒有更改
通常,您只會看到第一個數字,hello.so.1
因為第一個數字是識別庫「版本」所需的唯一內容,因為所有其他數字都是向後相容的。
ldconfig
維護一個表,其中列出系統上可用的共享庫以及該庫的路徑所在的位置。您可以透過執行以下命令來驗證這一點:
ldconfig -p
當為 Red Hat 之類的東西建置套件時,將在 RPM 建置時尋找二進位檔案中呼叫的共用程式庫並將其新增為套件的依賴項。因此,當您安裝軟體套件時,安裝程式將hello.so.1
透過檢查 來尋找系統上是否已安裝該軟體套件ldconfig
。
您可以透過執行以下操作來查看套件的依賴關係:
rpm -qpR hello.rpm
該系統(與 Windows 不同)允許hello.so
在系統上安裝多個版本,並同時由不同的應用程式使用。
答案4
libNAME.so 是編譯器/連結器首次尋找 -lNAME 指定的函式庫時所使用的檔名。共享庫文件內部有一個名為 SONAME 的欄位。當建置過程首次將程式庫本身連結到共用物件 (so) 時,會設定此欄位。該 SONAME 實際上是連結器在可執行檔中儲存的內容,具體取決於與其連結的共用物件。通常,SONAME 的形式為libNAME.so.MAJOR,只要庫與連結到它的現有可執行檔不相容,SONAME 就會更改,並且可以根據需要保留安裝庫的兩個主要版本(儘管只會指向一個版本進行開發)如 libNAME.so)此外,為了支援在庫的次要版本之間輕鬆升級,libNAME.so.MAJOR 通常是指向 libNAME.so.MAJOR.MINOR 等文件的連結。可以安裝新的次要版本,一旦完成,舊次要版本的連結將被跳到新的次要版本,立即升級所有新執行以使用升級後的庫。另請參閱我的回答Linux、GNU GCC、ld、版本腳本和 ELF 二進位格式 -- 它是如何運作的?