Linux下共享鏈接庫 (1)

 

共享鏈接庫當應用程序啓動時被加載。當一個共享鏈接庫被成功安裝後,所有的應用程序從此以後都會自動使用新的共享庫。實際上它要比這個更靈活更復雜,因爲 Linux 採用瞭如下方法允許你:

  1. 更新庫但是仍然支持應用程序使用老的,不向後兼容的版本;

  2. 當執行應用程序時可以覆蓋指定的庫甚至是庫中特定的函數;

  3. 就算應用程序正在運行並使用已經存在的庫,仍然可以做以上的事情。

 

爲了讓共享鏈接庫支持這些特性,我們必須遵循一些慣例和規範。首先你需要明白庫的各種名字,特別是 soname real name 。你也必須知道這些庫應該被放在文件系統中的什麼地方。

每一個共享鏈接庫都有一個特別的名字 soname soname 由前綴 lib ,庫名,擴展名 .so ,然後是 . 和一個版本號組成。版本號會隨着接口的變化而遞增。最底層的 C 庫是一個例外,因爲它不是以 lib 打頭。全限定的 soname 會以它所在的目錄作爲前綴。在一個運行的系統中全限定的 soname 只是 real name 的符號鏈接。

 

每個共享鏈接庫都有一個 real name ,它是包含真正庫代碼文件的名字。 Real name 是由 soname 後跟一個 . ,次版本號,另一個 . ,和發佈版本號組成。最後的 . 和發佈版本號是可選的。次版本號和發佈版本號支持配置控制,以此讓你知道現在安裝的庫是什麼版本。

另外,還有個名字用於編譯器請求鏈接庫,我們可以稱之爲 linker nam 。它只是 soname 去掉版本號。

 

管理動態鏈接庫的關鍵就是區分這些名字。在應用程序中,當它們內部列出自己需要的共享鏈接庫時,只要列出 soname 即可。恰恰相反,當你創建一個共享鏈接庫時,你只需要創建一個給定名字的庫即可 ( 可以附帶更具體的版本信息 ) 。當安裝庫的一個新版本時,你把它安裝在某個特定的文件夾然後運行程序 ldconfig Ldconfig 會檢測已經存在的文件並創建 soname 符號連接到 real name ,同時也會建立緩存文件 /etc/ld.so.cache

Ldconfig 並不會建立 link name 。典型地這應該在庫安裝的時候完成, linker name 只是簡單地作爲最新的 soname 或者 real name 的符號鏈接。我本推薦 linker name 應該是 soname 的符號鏈接,因爲在大多數場合如果你更新庫,你總是希望在鏈接時自動使用它。我問過 H.J.Lu 爲什麼 ldconfig 不自動建立 linker name 。他的解釋基本上是你可能想要使用最新的版本運行代碼,但是要用老版本來開發。所以, ldconfig 不會假設你到底需要把應用程序鏈接到什麼版本,所以,安裝程序要明確修改符號鏈接來更新鏈接器用什麼版本的庫。

 

因此, /usr/lib/libreadline.so.3 是一個全限定的 soname ldconfig 會設置符號鏈接到某個 real name 比如 /usr/lib/libreadline.so.3.0 。也會有一個 linker name /usr/lib/libreadline.so ,一個指向 /usr/lib/libreadline.so.3 的符號鏈接。

 

共享鏈接庫必須被放在文件系統的某個地方。大多數開源軟件都傾向於遵循 GNU 標準。 GNU 標準推薦當發佈源代碼時把所有庫默認安裝在 /usr/local/lib 下,所有的命令安裝在 /usr/local/bin 下。它也定義了一些關於如何覆蓋這些默認設置和調用安裝例程的約定。

但是 Filesystem Hierarchy Standard(FHS) 也討論了應該在發佈時將庫安裝在什麼目錄下。根據 FHS 規範,大部分庫都應該安裝在目錄 /usr/lib ,但是啓動時所需要的庫必須在目錄 /lib ,非系統庫應該在目錄 /usr/local/lib

 

這兩份文檔的規定並不衝突: GNU 規範推薦的默認目錄是針對源代碼的開發人員,而 FHS 推薦的默認目錄是對發佈者而言的。注意,如果你的庫調用了一些程序,並且這些程序只能被庫調用,那麼你應該把這些程序放在 /usr/local/libexec 目錄下 ( 對於發佈時的 /usr/libexec 目錄 )

 

GNU 基於 glibc 的系統中,包含所有的 Linux 操作系統,啓動 ELF 二進制可執行文件都會導致程序加載器被自動加載並執行。在 Linux 下,加載器是 /lib/ld-linux.so.X(X 是版本好 ) 。它會依次找到並加載所有其他應用程序用到的共享鏈接庫。

所以的搜索目錄在文件 /ect/ld.so.conf 中指定。很多 Red Hat 衍生的 Linux 發行版在該文件中並不包含目錄 /usr/local/lib

如果你只是想覆蓋庫中的一些方法,但是保持庫的其他部分不變,你可以在文件 /etc/ld.so.preload 中輸入該庫的名字。這個方法典型用於緊急的 patch 。發行版在發佈時通常不會包含這樣的文件。

 

在程序啓動時搜索所有的目錄會很低效,所以緩存會被用到。 ldconfig 默認會讀取文件 /etc/ld.so.conf ,建立合適的符號鏈接到動態鏈接目錄,接着會寫緩存到文件 /etc/ld.so.cache ,然後這些動態鏈接庫就可以被其他程序調用了。這大大加速了訪問鏈接庫的時間。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章