Ubuntu

為什麼在載入 SO 文件時會在末尾附加一個版本?

  • April 23, 2015

我使用 CMake 和 Ninja 建構了一個用 C++ 編寫的我的測試執行檔。我使用 gcc 4.8。我在 Ubuntu 14 上。

我執行 CMake 來配置 ninja 建構腳本,然後執行 ninja 來建構。我在 CMake 腳本中指定了libcrypto.so和其他 openssl文件作為目標依賴項。*.so

執行執行檔時,出現以下錯誤:

載入共享庫時出錯:libcrypto.so.1.0.0:無法打開共享對象文件:沒有這樣的文件或目錄

我的libcrypto.so文件就在測試執行檔旁邊:

-rw-r--r-- 1 robert domain users 1796847 Apr 20 15:43 libboost_wave.so
-rw-r--r-- 1 robert domain users  410916 Apr 20 15:43 libboost_wserialization.so
-rw-r--r-- 1 robert domain users 2251519 Apr 21 11:28 libcrypto.so
-rw-r--r-- 1 robert domain users  701627 Apr 20 15:43 libEGL.so
-rw-r--r-- 1 robert domain users 4255871 Apr 20 15:43 libGLES_CM.so
-rw-r--r-- 1 robert domain users 7550551 Apr 20 15:43 libGLESv2.so
-rw-r--r-- 1 robert domain users  949113 Apr 17 14:34 libsqlite.so
-rw-r--r-- 1 robert domain users  496298 Apr 21 11:28 libssl.so
-rwxr-xr-x 1 robert domain users 3099250 Apr 21 11:30 Test_UI_String*

(我正在執行的執行檔名為Test_UI_String

CMake 設置為在執行檔旁邊輸出共享庫,因為在 Windows(我最熟悉開發的地方)等其他平台上,DLL 文件需要在 EXE 旁邊才能找到和載入。

我對為什麼它附加1.0.0到庫文件的末尾感到困惑。它應該在最後沒有版本號的情況下查找它,因為當我連結依賴項時,它與libcrypto.so上面顯示的目錄中的名稱相同。

我想更好地理解這裡的行為,但是我的主要問題基本上是關於如何讓它按預期工作(查找與執行檔位於同一目錄中的庫依賴項)。

-l當連結器生成執行檔(或另一個共享庫)時,它會通過名稱的前綴lib和後綴來搜尋請求使用的庫.so。例如,如果您要求,-lcrypto那麼它會搜尋libcrypto.so.

找到庫後,連結器會從庫中讀取一條稱為 soname 的元數據。soname 然後被記錄到正在建構的執行檔中,這就是在執行時再次搜尋相同庫時使用的名稱。soname 當然可以與連結時實際找到庫的名稱不同。

此功能的案例是能夠同時在系統上安裝多個不同的、不兼容的庫版本。以下是它的一般使用方式。

首先,讓我描述一下在沒有這個約定的情況下會發生什麼:

開發標頭檔(.h文件)與庫的特定版本耦合,.so文件也包含該版本:

/usr/include/mylibrary.h
/usr/lib/libmylibrary.so

myapp已針對此版本的庫編譯了一個應用程序,並/usr/lib/libmylibrary.so在執行時載入它。

稍後,該庫將升級到新版本。.h和文件都.so替換為新版本。不幸的是,新版本的 ABI 不兼容。

現在,當myapp執行時,它會崩潰或表現出未定義的行為,因為它是針對一個具有一個 ABI 的版本編譯的,但它在執行時載入了不同的版本。

soname 約定會發生什麼:

該庫安裝如下:

/usr/include/mylibrary.h
/usr/lib/libmylibrary.so -> libmylibrary.so.1
/usr/lib/libmylibrary.so.1

/usr/lib/libmylibrary.so.1在其中嵌入了 soname libmylibrary.so.1

建構時myapp,它會定位/usr/lib/libmylibrary.so但連結器遵循符號連結並實際載入/usr/lib/libmylibrary.so.1. 此外, sonamelibmylibrary.so.1是實際記錄在裡面的內容myapp。在執行時,直接myapp載入/usr/lib/libmylibrary.so.1,繞過符號連結。

稍後,該庫會升級到具有不兼容 ABI 的新版本。.h和文件都.so替換為新版本。出現一個新文件libmylibrary.so.2。舊版本中的libmylibrary.so.1那個被單獨留下。

/usr/include/mylibrary.h
/usr/lib/libmylibrary.so -> libmylibrary.so.2
/usr/lib/libmylibrary.so.1
/usr/lib/libmylibrary.so.2

現在,當myapp被執行時,它會繼續載入libmylibrary.so.1並且仍然按預期執行。但如果安裝了其他新應用程序或myapp重新編譯了自身,則會遵循符號連結並使用新版本。


您看到的問題是,當您的應用程序被連結時,連結器發現其中包含 soname 的庫libcrypto.so.1.0.0

您的副本是否libcrypto.so使用 soname if 生成libcrypto.so.1.0.0

另一種可能性,很可能在這裡,是您的副本中libcrypto.so沒有 soname,但連結器實際上找到並使用了(來自 OpenSSL)的系統版本,libcrypto.so這就是它獲得 soname 的地方。

引用自:https://unix.stackexchange.com/questions/197679