linux下靜態庫、動態庫相關問題總結

  前段時間項目中用到了對方給的庫文件,從最初的不會用到現在小有心得,並且在看了網上很多大牛的博客後,總結下發在這裏。

下一篇會發一篇關於在交叉編譯環境下,靜態庫和動態庫加載的問題。

 

一、靜態庫、動態庫的概念

      庫文件是一些函數、變量的集合,已編譯過的代碼。一般分爲靜態庫和動態庫兩種。

靜態庫: 靜態是指每個用到該庫的應用程序都擁有一份自己的庫拷貝;應用程序運行的時候,即使將庫刪除也沒有問題,因爲應用程序自己已經有了自己的拷貝。但是這也稱爲了它的缺點,因爲靜態庫如果發生改變的話,那麼應用程序也就需要重新進行編譯了

 

動態庫: 一個共享庫有可能被多個所有應用程序共享。因此,對每個應用程序來說,即使不再使用某個共享庫,也不應將其刪除。此外,應用程序需要正確的環境變量設置(LD_LIBRARY_PATH),從而找到共享庫所在的位置,否則,應用程序運行時會報告找不到這個庫。

 

二、靜態庫、動態庫的創建

創建:
無論靜態庫還是動態庫,創建都分爲兩步,第一步創建目標文件,第二步生產庫。
1).靜態庫的創建:
#gcc -c test.c -o test.o
#ar rcs libtest.a test.o
名字爲libtest.a的靜態庫就生產了,其中選項:
r 表明將模塊加入到靜態庫中;
c 表示創建靜態庫;
s 表示生產索引;
還有更多選項像增加、刪除庫中的目標文件,包括將靜態庫解包等可以通過man來獲得。


2).動態庫的創建:
#gcc -fPIC -c test.c -o test.c
#gcc --share test.o -o libtest.so
-fPIC 爲了跨平臺

 

三、靜態庫、動態庫的使用

 環境變量配置:

庫文件在連接(靜態庫和共享庫)和運行(僅限於使用共享庫的程序)時被使用,其搜索路徑是在系統中進行設置的。
一般 Linux 系統把 /lib 和 /usr/lib 兩個目錄作爲默認的庫搜索路徑,所以使用這兩個目錄中的庫時不需要進行設置搜索路徑即可直接使用。對於處於默認庫搜索路徑之外的庫,需要將庫的位置添加到庫的搜索路徑之中。設置庫文件的搜索路徑有下列兩種方式,可任選其一使用:
在環境變量 LD_LIBRARY_PATH 中指明庫的搜索路徑。 比如一個libtest.a庫在/home/test/lib目錄下,在終端內

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/test/lib
在 /etc/ld.so.conf 文件中添加庫的搜索路徑。添加方法也極其簡單,將庫文件的絕對路徑直接寫進去就OK了,一行一個,例如:

/usr/local/lib
/opt/lib

需要注意的是:第二種搜索路徑的設置方式對於程序連接時的庫(包括共享庫和靜態庫)的定位已經足夠了,但是對於使用了共享庫的程序的執行還是不夠的。這是因爲爲了加快程序執行時對共享庫的定位速度,避免使用搜索路徑查找共享庫的低效率,所以是直接讀取庫列表文件 /etc/ld.so.cache 從中進行搜索的。/etc/ld.so.cache 是一個非文本的數據文件,不能直接編輯,它是根據 /etc/ld.so.conf 中設置的搜索路徑由 /sbin/ldconfig 命令將這些搜索路徑下的共享庫文件集中在一起而生成的(ldconfig 命令要以 root 權限執行)。

        因此,爲了保證程序執行時對庫的定位,在 /etc/ld.so.conf 中進行了庫搜索路徑的設置之後,還必須要運行 /sbin/ldconfig 命令更新 /etc/ld.so.cache 文件之後纔可以。ldconfig ,簡單的說,它的作用就是將/etc/ld.so.conf列出的路徑下的庫文件緩存到/etc/ld.so.cache 以供使用。因此當安裝完一些庫文件,(例如剛安裝好glib),或者修改ld.so.conf增加新的庫路徑後,需要運行一下 /sbin/ldconfig使所有的庫文件都被緩存到ld.so.cache中,如果沒做,即使庫文件明明就在/usr/lib下的,也是不會被使用的,結果編譯過程中抱錯,缺少xxx庫,去查看發現明明就在那放着,這時候會很是鬱悶的。

 

 使用:
編譯鏈接目標程序的方法是一樣的:
#gcc main.c -L. -ltest -o main
-L.指定現在本目錄下搜索庫,如果沒有,會到系統默認的目錄下搜索,一般爲/lib、/usr/lib下。
對於靜態庫,這個步驟之後就可以將libtest.a庫刪掉,因爲它已經被編譯進了目標程序,不再需要它了。
而對於動態庫,libtest.so庫只是在目標程序裏做了標記,在運行程序時纔會動態加載,那麼從哪加載呢?加載目錄會由/etc/ld.so.conf來指定,一般默認是/lib、/usr/lib,所以要想讓動態庫順利加載,你可以將庫文件copy到上面的兩個目錄下,或者設置export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/XXX/YYY,後面爲你自己動態庫的目錄,再或者修改/etc/ld.so.conf文件,把庫所在的路徑加到文件末尾,並執行ldconfig刷新。這樣,加入的目錄下的所有庫文件都可見。

 

四、靜態庫、動態庫的加載順序

GCC在鏈接過程中,對參數中的庫的順序是有要求的,參數右側的庫會先於左側的庫加載,也就是說參數的解析是從右往左的。

    假設庫B依賴與庫A,則鏈接的時候要寫爲:
       gcc -o bin B A
   如果寫爲:
       gcc -o bin A B
   則在B中引用的A中的內容就會無法鏈接通過
如果在同一目錄下,既有靜態庫又有動態庫,則在默認情況下是先加載動態庫,因爲對gcc來說默認方式是加載動態庫,如果要讓靜態庫優先加載的話,則需要加上-static參數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章