1.什麼是庫
在windows平台和linux 平台下都大量存在著庫。
本質上來說庫是一種可執行**的二進位制形式,可以被作業系統載入記憶體執行。
由於windows和linux 的本質不同,因此二者庫的二進位制是不相容的。
本文僅限於介紹linux 下的庫。
2.庫的種類
linux 下的庫有兩種:靜態庫和共享庫(動態庫)。
二者的不同點在於**被載入的時刻不同。
靜態庫的**在編譯過程中已經被載入可執行程式,因此體積較大。
共享庫的**是在可執行程式執行時才載入記憶體的,在編譯過程中僅簡單的引用,因此**體積較小。
3.庫存在的意義
庫是別人寫好的現有的,成熟的,可以復用的**,你可以使用但要記得遵守許可協議。
現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的**都從零開始,因此庫的存
在意義非同尋常。
共享庫的好處是,不同的應用程式如果呼叫相同的庫,那麼在記憶體裡只需要有乙份該共享庫
的例項。
4.庫檔案是如何產生的在linux 下
靜態庫的字尾是.a ,它的產生分兩步
step 1.由原始檔編譯生成一堆.o ,每個.o 裡都包含這個編譯單元的符號表
step 2.ar命令將很多.o 轉換成.a ,成文靜態庫
動態庫的字尾是.so ,它由gcc 加特定引數編譯產生。
例如: 有乙個print.c檔案,內容如下:
###########################################
#include
###########################################
#gcc -c print.c
#gcc -shared -fpic -o libprint.so print.o5.庫檔案是如何命名的,有沒有什麼規範
在linux 下,庫檔案一般放在/usr/lib /lib 下,
靜態庫的名字一般為lib***x.a ,其中***x是該lib的名稱
動態庫的名字一般為lib***x.so.major.minor ,***x是該lib的名稱,major是主版本號,
minor是副版本號
6.如何知道乙個可執行程式依賴哪些庫
ldd 命令可以檢視乙個可執行程式依賴的共享庫,
#gcc -o hello hello.c -lprint
[root@localhost testdir]# ldd hello
linux-gate.so.1 => (0x00c0b000)
libprint.so => /usr/lib/libprint.so (0x00767000)
libc.so.6 => /lib/libc.so.6 (0x00110000)
可以看到hello依賴的 庫
7.可執行程式在執行的時候如何定位共享庫檔案
當系統載入可執行**時候,能夠知道其所依賴的庫的名字,但是還需要知道絕對路徑
此時就需要系統動態載入器(dynamic linker/loader)
對於elf格式的可執行程式,是由ld-linux.so* 來完成的,它先後搜尋elf檔案的 dt_rpath
段—環境變數ld_library_path—/etc/ld.so.cache 檔案列表—/lib/,/usr/lib目錄找
到庫檔案後將其載入記憶體
8.在新安裝乙個庫之後如何讓系統能夠找到他
基本概念
庫有動態與靜態兩種,動態通常用.so 為字尾,靜態用.a 為字尾。
例如:libhello.so libhello.a 為了在同一系統中使用不同版本的庫,可以在庫檔名後加上版本號為字尾, 例如: libhello.so.1.0, 由於程式連線預設以.so 為檔案字尾名。所以為了使用這些庫,通常使用建立符號連線的方式。
ln -s libhello.so.1.0 libhello.so.1
ln -s libhello.so.1 libhello.so
1、使用庫
當要使用靜態的程式庫時,聯結器會找出程式所需的函式,然後將它們拷貝到執行檔案,由於這種拷貝是完整的,所以一旦連線成功,靜態程式庫也就不再需要了。然 而,對動態庫而言,就不是這樣。動態庫會在執行程式內留下乙個標記指明當程式執行時,首先必須載入這個庫。由於動態庫節省空間,linux 下進行連線的預設操作是首先連線動態庫,也就是說,如果同時存在靜態和動態庫,不特別指定的話,將與動態庫相連線。 現在假設有乙個叫hello的程式開發包,它提供乙個靜態庫libhello.a 乙個動態庫libhello.so, 乙個標頭檔案hello.h,標頭檔案中提供sayhello() 這個函式 /* hello.h */ void sayhello(); 另外還有一些說明文件。
這乙個典型的程式開發包結構 與動態庫連線 linux 預設的就是與動態庫連線,下面這段程式testlib.c 使用hello庫中的sayhello() 函式
/*testlib.c*/
#include
#include
int main()
使用如下命令進行編譯 $gcc -c testlib.c -o testlib.o
用如下命令連線: $gcc testlib.o -lhello -o testlib
$gcc testlib.o -o testlib -wi,-bstatic -lhello
注:這個特別的"-wi,-bstatic"引數,實際上是傳給了聯結器ld 。指示它與靜態庫連線,如果系統中只有靜態庫當然就不需要這個引數了。 如果要和多個庫相連線,而每個庫的連線方式不一樣,比如上面的程式既要和libhello 進行靜態連線,又要和libbye 進行動態連線,其命令應為:
$gcc testlib.o -o testlib -wi,-bstatic -lhello -wi,-bdynamic -lbye
2、動態庫的路徑問題 為了讓執行程式順利找到動態庫,有三種方法:
(1) 把庫拷貝到/usr/lib 和/lib 目錄下。
(2) 在ld_library_path環境變數中加上庫所在路徑。
例如動態庫libhello.so在/home/ting/lib目錄下,以bash為例,使用命令:
$export ld_library_path=$ld_library_path:/home/ting/lib
(3) 修改/etc/ld.so.conf檔案,把庫所在的路徑加到檔案末尾,並執行ldconfig 重新整理。這
樣,加入的目錄下的所有庫檔案都可見。
3、檢視庫中的符號
有時候可能需要檢視乙個庫中到底有哪些函式,nm命令可以列印出庫中的涉及到的所有符
號。庫既可以是靜態的也可以是動態的。nm列出的符號有很多,常見的有三種:
一種是在庫中被呼叫,但並沒有在庫中定義(表明需要其他庫支援),用u表示;
一種是庫中定義的函式,用t 表示,這是最常見的;
另外一種是所謂的「弱 態」 符號,它們雖然在庫中被定義,但是可能被其他庫中的同名符號
覆蓋,用w表示。
4、生成庫
第一步要把源**編繹成目標**。
以下面的**為例,生成上面用到的hello庫:
/* hello.c */
#include
void sayhello()
用gcc 編繹該檔案,在編繹時可以使用任何全法的編繹引數,例如-g加入除錯**等: gcc
-c hello.c -o hello.o
(1) 連線成靜態庫 連線成靜態庫使用ar命令,其實ar是archive 的意思
$ar crv libhello.a hello.o
(2) 連線成動態庫 生成動態庫用gcc 來完成,由於可能存在多個版本,因此通常指定版本號:
$gcc -shared -wl,-soname,libhello.so.1 -o libhello.so.1.0 hello.o
另外再建立兩個符號連線:
$ln -s libhello.so.1.0 libhello.so.1
$ln -s libhello.so.1 libhello.so
這樣乙個libhello 的動態連線庫就生成了。最重要的是傳gcc -shared 引數使其生成是動態庫而不是普通執行程式。 -wl 表示後面的引數也就是-soname,libhello.so.1 直接傳給聯結器ld 進行處理。實際上,每乙個庫都有乙個soname ,當聯結器發現它正在查詢的程式庫中有這樣乙個名稱,聯結器便會將soname 嵌入鏈結中的二進位制檔案內,而不是它正在執行的實際檔名,在程式執行期間,程式會查詢擁有 soname名字的檔案,而不是庫的檔名,換句話說,soname 是庫的區分標誌。 這樣做的目的主要是允許系統中多個版本的庫檔案共存,習慣上在命名庫檔案的時候通常與soname 相同 lib***x.so.major.minor 其中,***x是庫的名字,major是主版本號,minor 是次版本號
鏈結裝載庫
一般應用程式記憶體空間有如下區域 棧棧儲存了乙個函式呼叫所需要的維護資訊,常被稱為堆疊幀 stack frame 或活動記錄 activate record 一般包含以下幾方面 堆堆分配演算法 段錯誤 segment fault 或 非法操作,該記憶體位址不能 read write 典型的非法指標解...
裝載 鏈結與庫
第五部分 windows動態鏈結 1 dll函式和變數必須在檔案顯示是匯入還是匯出,declspec dllexport 匯出,declspec dllimport 匯入.建立dll檔案的時候.c檔案生成.dll,lib,exp檔案,然後用.lib檔案和exe中的.c檔案生成的目標檔案鏈結在一起,生...
鏈結 裝載與庫
鏈結 裝載與庫 在linux下,當我們使用 gcc來編譯 helloword 程式時,只需要 gcc hello.c a.out hello world 其中實際包括4步驟 預處理 prepressinng 編譯 compliation 彙編 assembly 鏈結 linking 1.預編譯 gc...