linux C/C++ 靜態庫、共享庫

C語言庫——靜態庫、共享庫



      我們在編寫一個C語言程序的時候,經常會遇到好多重複或常用的部分,如果每次都重新編寫固然是可以的,不過那樣會大大降低工作效率,並且影響代碼的可讀 性,更不利於後期的代碼維護。我們可以把他們製作成相應的功能函數,使用時直接調用就會很方便,還可以進行後期的功能升級。

     例如我要在一段代碼中多次交換兩個變量的值,我可以在代碼中多次寫入

i=x;
x=y;
y=i;

       不過這樣未免有點麻煩我們可以編寫一個change_two_int()函數進行簡化。
定義如下函數:
void change_two_int(int *a,int *b)
  {
     int c;
     c=*a;
     *a=*b;
     *b=c;
   }
    這樣每次要進行交換時只需調用 change_two_int(&x , &y);即可,是否方便了許多?

       那麼我們要討論的和這些有什麼關係呢?庫通俗的說就是把這些常用函數的目標文件打包在一起,提供相應函數的接口,便於程序員使用。庫是別人寫好的現有的, 成熟的,可以複用的代碼,我們只需要知道其接口如何定義,便可以自如使用。

      現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常。比如我們常使用的printf函數,就是c標準庫 提供的函數。我們在使用時只需要包含相應的頭文件就可以使用(非靜態編譯還要有相應的庫文件)。而不用關心printf函數具體是如何實現的,這樣就大大 提高了程序員編寫代碼的效率。從使用方法上分庫大體上可以分爲兩類:靜態庫和共享庫。在windows中靜態庫是以 .lib 爲後綴的文件,共享庫是以.dll 爲後綴的文件。在linux中靜態庫是以 .a 爲後綴的文件,共享庫是以 .so爲後綴的文件。
以linux 下的靜態庫和動態庫爲例我們研究一下,首先我們看一下他們的生成方式

靜態庫:
首先將 源文件編譯成目標文件:gcc –c a.c b.c
生成靜態庫:ar –rc libstatic.a a.o b.o

共享庫:
同靜態庫一樣編譯成目標文件:gcc –c a.c b.c
生成共享庫:gcc –fPIC –shared –o libshared.so a.o b.o

       由此可見靜態庫和動態庫都是對目標文件的處理,也可以說庫文件已經是機器碼文件了,靜態庫和共享庫的加載過程有很大的區別。

靜態庫的鏈接方法:
gcc –o staticcode –L. –lstatic main.c –static(默認庫在當前文件夾)

共享庫的鏈接方法: 
gcc –o sharedcode  -L. –lshared main.c(默認庫在當前文件夾)

      當程序與靜態庫連接時,庫中目標文件所含的所有將被程序使用的函數的機器碼被copy到最終的可執行文件中。這就會導致最終生成的可執行代碼量相對變 多,相當於編譯器將代碼補充完整了,這樣運行起來相對就快些。不過會有個缺點: 佔用磁盤和內存空間. 靜態庫會被添加到和它連接的每個程序中,而且這些程序運行時, 都會被加載到內存中. 無形中又多消耗了更多的內存空間.

       與共享庫連接的可執行文件只包含它需要的函數的引用表,而不是所有的函數代碼,只有在程序執行時,那些需要的函數代碼才被拷貝到內存中。這樣就使可執行文 件比較小,節省磁盤空間,更進一步,操作系統使用虛擬內存,使得一份共享庫駐留在內存中被多個程序使用,也同時節約了內存。不過由於運行時要去鏈接庫會花 費一定的時間,執行速度相對會慢一些,總的來說靜態庫是犧牲了空間效率,換取了時間效率,共享庫是犧牲了時間效率換取了空間效率,沒有好與壞的區別,只看 具體需要了。

        另外,.一個程序編好後,有時需要做一些修改和優化,如果我們要修改的剛好是庫函數的話,在接口不變的前提下,使用共享庫的程序只需要將共享庫重新 編譯就可以了,而使用靜態庫的程序則需要將靜態庫重新編譯好後,將程序再重新編譯一便。

庫操作的相關命令

nm

功能:
       列出編入目標文件或二進制文件的所有符號。用途一:查看程序調用什麼函數;用       途二:查看一個給定的庫或目標文件是否提供了所需的函數。

語法:nm [options] file

常用選項:
-C 將符號名轉換爲用戶級的名字。在讓C++函數名可讀方面特別有用。
-s 當用於.a文件時,輸出把符號名映射到定義該符號的模塊或成員名的索引。
-u 只顯示未定義的符號,即在被檢查的文件外部定義的文件。
-l  使用調試信息輸出定義每個符號的行號,或未定義符號的重要位項。

ar

功能:將多個.o文件組合到一起成爲.a文 件。

語法:ar [options] lib*.a *.o

常用選項:
-c 如果存檔文件不存在,則創建,並不顯示ar發出的警告。
-q 把*.o添加到存檔文件末尾而不檢查是否進行替換。
-r  向存檔文件中插入.o文件,替換已有的任何同名文件,新成員添加到文檔末尾。
-s 創建或升級從符號到.a文件之間的交叉索引映射表,並加入到.a文件中。
   等價與ranlib [*.a]。執行該命令後,可用nm –s來查看生成的索引。

ldd
功能:顯示可執行程序運行所需的共享庫。
語法
ldd [options] file

常用選項:
-d 執行重定位並報告所有丟失的函數。
-r 執行對函數和數據對象的重定位並報告丟失的任何函數或數據對象。

ldconfig

功能:
      在默認搜尋目錄(/lib和/usr/lib)及動態庫配置文件/etc/ld.so.conf中所列的目錄下,搜索出可共享的動態鏈接庫 (lib*.so*),進而創建出動態裝入程序(ld.so)所需的連接和緩存文件。緩存文件默認爲/etc/ld.so.cache,此文件保存了已排 好序的動態鏈接庫名字列表。該在系統啓動時會運行,而當用戶安裝了一個新的動態鏈接庫時,就需要手工運行這個命令。

語法:
ldconfig [options] path

例如:ldconfig /root/lib讓系統共享/root/lib目錄下的動態鏈接庫,即在/etc/ld.so.cache中添加指定目錄下的共享庫。[注意]若該目錄 不在/lib,/usr/lib,/etc/ld.soconf所列的目錄列表裏,則再次運行ldconf時,此目錄下的動態鏈接庫就不被系統共享了。

常用選項:
-v 更新/etc/ld.so.cache的內容,列處每個庫的版本號,掃描的目錄和所有創建和更新的鏈接。
-p 僅顯示/etc/ld.so.cache的內容,即ld.so所知道的共享庫的當前列表。
-n  ldconf僅掃描-n命令所指定的目錄
-f CONF   指定動態鏈接庫的配置文件爲CONF,系統默認爲/etc/ld.so.conf。
-c CACHE  指定生成的緩存文件爲CACHE,系統默認爲/etc/ld.so.cache。
當ldconf不帶選項時,僅更新高速緩衝文件。 

環境變量
$LD_PRELOAD      由空格分隔的共享庫列表,在其它庫之前加載,使它們有機會覆蓋或重新定義標準庫。
$LD_LIBRARY_PATH 由冒號分隔的目錄清單,都是共享庫搜索時會訪問的目錄。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章