為什麼在載入 SO 文件時會在末尾附加一個版本?
我使用 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
在其中嵌入了 sonamelibmylibrary.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 的地方。