天天看點

Linux中關于動态(共享)庫的設定

前言:關于Linux中的動态共享庫是如何使用的,程式在執行的時候是如何找到的,我們該怎麼去設定,可以參考前面的幾篇文章。

C/C++中關于靜态連結庫(.a)、動态連結庫(.so)的編譯與使用

VSCode開發C、C++環境搭建系列(二)——GCC/G++編譯器對頭檔案、靜态庫、動态庫的搜尋路徑詳解

本文會設計主要四個概念:

/etc/ld.so.conf、/etc/ld.so.conf.d、/etc/ld.so.cache、ldconfig

回顧前面的關于動态連結庫加載搜尋的順序,有:

  • gcc在編譯的時候通過  -L參數  手動指定的搜尋路徑
  • 環境變量LD_LIBRARY_PATH指定的動态庫搜尋路徑;
  • 配置檔案/etc/ld.so.conf中指定的動态庫搜尋路徑;(和本文就有關系了)
  • 再找内定目錄/lib:/usr/lib:/usr/local/lib這是這些安裝GCC套件的時候所安裝的那些目錄

前面已經說明了動态共享庫的一點基本原理,接下來我們要探讨一下怎麼設定程式尋找動态共享庫的行為。

一、Linux作業系統上面的動态共享庫大緻分為三類

1、作業系統級别的共享庫和基礎的系統工具庫

比方說libc.so, libz.so, libpthread.so等等,這些系統庫會被放在/lib和/usr/lib目錄下面,如果是64位作業系統,還會

有/lib64和/usr /lib64目錄。如果作業系統帶有圖形界面,那麼還會有/usr/X11R6/lib目錄,如果是64位作業系統,還

有/usr/X11R6 /lib64目錄。此外還可能有其他特定Linux版本的系統庫目錄。

這些系統庫檔案的完整和版本的正确,確定了Linux上面各種程式能夠正常的運作。常見的如下:

/lib

/usr/lib

/lib64

/usr /lib64

/usr/X11R6 /lib64

等等

2、應用程式級别的系統共享庫

并非作業系統自帶,但是可能被很多應用程式所共享的庫,一般會被放在/usr/local/lib和/usr/local/lib64這兩個目錄下面。很多

你自行編譯安裝的程式都會在編譯的時候自動把/usr/local/lib加入gcc的-L參數,而在運作的時候自動到/usr/local/lib下面去尋

找共享庫。

以上兩類的動态共享庫,應用程式會自動尋找到他們,并不需要你額外的設定和擔心。這是為什麼呢?因為以上這些目錄預設就被加入到動态連結程式的搜尋路徑裡面了。常見一些如下:

/usr/local/lib

/usr/local/lib64

3、應用程式獨享的動态共享庫

有很多共享庫隻被特定的應用程式使用,那麼就沒有必要加入系統庫路徑,以免應用程式的共享庫之間發生版本沖突。是以Linux還可以通過設定環境變量 LD_LIBRARY_PATH來臨時指定應用程式的共享庫搜尋路徑,就像我們上面舉的那個例子一樣,我們可以在應用程式的啟動腳本裡面預先設定 LD_LIBRARY_PATH,指定本應用程式附加的共享庫搜尋路徑,進而讓應用程式找到它。

二、前言中提到的四個概念

2.1 /etc/ld.so.conf 配置檔案——定義了動态連結庫的搜尋目錄有哪一些,和LD_LIBRARY_PATH異曲同工

根據前面的說法,根據動态共享連結庫的搜尋順序,/etc/ld.so.conf 是排在第三位的。我們自己安裝的一些動态連結庫所在的位置如果要被其他的程式所适用的話,除了通過設定環境變量LD_LIBRARY_PATH之外,還可以在/etc/ld.so.conf檔案中添加對應的路徑,也是可以的。

比如我們在搭建深度學習開發環境的時候,安裝了CUDA之後,常常需要配置環境變量如下:

export LD_LIBRARY_PATH=/usr/local/cuda10.0/lib64:$LD_LIBRARY_PATH
           

除此之外,我們也可以将這個動态共享連結庫的路徑放在 /etc/ld.so.conf 檔案裡面,給/etc/ld.so.conf檔案添加如下内容:

/usr/local/cuda/lib64
           

再比如:

假設我們自己編譯安裝的ImageMagick圖形庫在/usr/local/ImageMagick目錄下面,并且希望其他應用程式都可以使用ImageMagick的動态共享庫,那麼我們隻需要把/usr/local/ImageMagick/lib目錄加入/etc /ld.so.conf檔案裡面,即

/usr/local/ImageMagick/lib
           

然後執行:

ldconfig   # 使用此指令需要有root權限
           

指令即可。

ldcofig将搜尋以上所有的目錄,為共享庫建立一個緩存檔案/etc/ld.so.cache。

這裡有引出了另外兩個概念

2.2 ldconfig指令和 /etc/ld.so.cache檔案

(1)動态裝入器——dynamic loader

  前面說了動态連結庫的搜尋順序是從“四個地方”進行搜尋,那麼這個搜尋的過程是誰來完成的呢?Linux 的哪部分負責将這些程式和所有必需的共享庫一起裝入,以使它們能正确執行呢?答案是動态裝入器(dynamic loader),它實際上是您在 ln 的 ldd 清單中看到的作為共享庫相關性列出的 ld-linux.so.2 庫。動态裝入器負責裝入動态連結的可執行程式運作所需的共享庫。

動态裝入器找到共享庫要依靠兩個檔案 — /etc/ld.so.conf 和 /etc/ld.so.cache。如果您對 /etc/ld.so.conf 檔案進行 cat 操作,您可能會看到一個與下面類似的清單:

  $ cat /etc/ld.so.conf

  /usr/X11R6/lib

  /usr/lib/gcc-lib/i686-pc-linux-gnu/2.95.3

  /usr/lib/mozilla

  /usr/lib/qt-x11-2.3.1/lib

  /usr/local/lib
           

ld.so.conf 檔案包含一個所有目錄(/lib 和 /usr/lib 除外,它們會自動包含在其中)的清單,動态裝入器将在其中查找共享庫。

但是在動态裝入器能“看到”這一資訊之前,必須将它轉換到 ld.so.cache 檔案中。可以通過運作 ldconfig 指令做到這一點:

ldconfig
           

當 ldconfig 操作結束時,您會有一個最新的 /etc/ld.so.cache 檔案,它反映您對 /etc/ld.so.conf 所做的更改。從這一刻起,動态裝入器在尋找共享庫時會檢視您在 /etc/ld.so.conf 中指定的所有新目錄。

總結:每次給 /etc/ld.so.conf 添加了新的内容之後,都需要使用 ldconfid 指令來重新生成緩存檔案 /etc/ld.so.cache。這樣才能使用

即一個流程是:

在/etc/ld.so.conf中添加路徑——>使用ldconfig指令——>得到 /etc/ld.so.cache檔案

(2)ldconfig 技巧——檢視 ldconfig 可以自動搜尋到的所有共享庫,請輸入:

 ldconfig -p | less
           

(3)如何檢視自己的 /etc/ld.so.cache中是否有指定的庫

比如,為了确認ldconfig已經搜尋到ImageMagick的庫,我們可以用上面介紹的strings指令從ld.so.cache裡面抽取文本資訊來檢查一下:

strings /etc/ld.so.cache | grep ImageMagick
           

輸出結果為:

/usr/local/ImageMagick/lib/libWand.so.10
/usr/local/ImageMagick/lib/libWand.so
/usr/local/ImageMagick/lib/libMagick.so.10
/usr/local/ImageMagick/lib/libMagick.so
/usr/local/ImageMagick/lib/libMagick++.so.10
/usr/local/ImageMagick/lib/libMagick++.so
           

已經成功了!

當然,也不是說一定要将動态庫的路徑添加到/etc/ld.so.conf裡面才行,我直接使用LD_lIBRARY_PATH也是可以的,比如我的cuda環境,因為是多使用者管理自己的不同的CUDA環境,對于沒有root權限的使用者而言,隻能夠使用LD_lIBRARY_PATH,

而要使用ldconfig這個指令,通常它位于/sbin下,是root使用者使用的指令,需要root權限。

2.3 /etc/ld.so.conf.d——是一個目錄

它是一個目錄,裡面有很多的 xxx.conf 檔案,比如我的伺服器上面的這個目錄下面有:

cuda.conf
...
...
...等等
           

打開其中的一個conf檔案檢視,比如打開cuda.conf檔案,裡面的内容如下:

/usr/local/cuda/lib64
這其實就是一個路徑,我打開發現 /usr/local/cuda是一個軟連接配接快捷方式,指向
/usr/local/cuda-9.0/,是以實際上是 /usr/local/cuda-9.0/lib64
           

然後我們打開 /etc/ld.so.conf 進行檢視裡面有一句話

include /etc/ld.so.conf.d/*.conf 

# 實際上就是包含所有的 etc/ld.so.conf.d 目錄之下的所有的 xxx.conf 檔案中的路徑,相當于是一些列的路徑被包含進來了
           

是以我們需要配置一個動态連結庫的路徑,除了直接将路徑寫在  etc/ld.so.conf  檔案裡面以外,還可以有另外一種方式

  • 第一步:在 etc/ld.so.conf.d在中建立一個 xxx.conf 檔案,然後将動态連結庫的路徑寫在這裡面
  • 第二步:然後再etc/ld.so.conf使用 include 導入所有的 etc/ld.so.conf.d 中的路徑
  • 第三步:再使用ldconfig産生 etc/ld.so.cache 緩存檔案

當然,這都是需要root權限的。

繼續閱讀