linux C C 之庫編譯靜態庫 共享庫

2021-08-31 21:58:12 字數 3417 閱讀 3731

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

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

i=x;

x=y;

y=i;

不過這樣未免有點麻煩我們可以編寫乙個change_two_int()函式進行簡化。

定義如下函式:

void change_two_int(int *a,int *b)

這樣每次要進行交換時只需呼叫 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 由冒號分隔的目錄清單,都是共享庫搜尋時會訪問的目錄

Linux C C 生成並使用靜態庫 動態庫

在windows下靜態庫的字尾為 lib 動態庫字尾為 dll 而在linux下靜態庫的字尾為 a 動態庫的字尾為 so。那麼什麼是靜態庫呢?在我們的專案開發中,有些 會被反覆使用,那麼這時我們便可將這些 編譯成庫的形式來呼叫,像靜態庫就是在可執行檔案中包含庫 的乙份完整拷貝,但這種方式有個很嚴重的...

編譯靜態庫編譯動態庫

編譯靜態庫 cr標誌告訴ar將object檔案封裝 archive 我們可以使用nm s 命令來檢視.a檔案的內容 ar cr libmyhello.a hello.o 或 cvr 編譯動態庫 gcc c fpic test1.c gcc c fpic test2.c fpic告訴gcc將源 編譯成...

靜態庫 a編譯和靜態庫 a合併

第一步 生成test.o目標檔案,使用gcc c test.c o test.o命令。第二步 使用ar將test.o打包成libtest.a靜態庫,使用ar rcs o libtest.a test.o命令 第三步 生成libtest.a靜態庫後,可以使用命令ar t libtest.a檢視libt...