linux動 靜態庫的生成和使用

2021-04-14 00:43:03 字數 4206 閱讀 1857

在小烏的眼裡,庫檔案就是資源檔案,也沒有什麼難以理解的;可是如果真要問得深入一點:「動態鏈結庫和靜態鏈結庫有什麼區別?」,「怎麼做乙個動態鏈結庫?」,「怎麼生成靜態/動態鏈結庫?」,「什麼叫顯示/隱示呼叫?」。。。小烏就鬱悶了,所以今天決定要拍死這些問題。

window下面的動/靜態鏈結庫檔名分別為:.dll和.lib;

linux下則為:.so或.so.x和.a;.so檔案的標準形式應該為:lib***.so或lib***.so.y,字首的lib是為了系統能識別它,字尾的.y則是版本號,可有可無;靜態鏈結庫對於linux來說叫共享庫或許來的比較標準,靜態庫檔案.a則可以看做是目標檔案.o的乙個集合,形式也必須為lib***.a。

.lib對.a,.dll對.so。或許從名字及應用的os來看,沒什麼太大的聯絡,但實際上都是換湯不換藥,乙個故事,所以在這裡拿到一起來說。依小烏之見,所有的庫檔案實際上都是資源檔案,也就是說,作為「備選的資源」而存在,只將必要的部分匯入到自己的程式中;但是區別是:靜態庫必要的目標**的是在對程式編譯的時候被加入到程式中,而動態庫的目標**是在被呼叫的時候加入到程式中,所以相比之下動態庫更加靈活,也沒有象靜態庫那樣存在對系統資源浪費的問題。但是靜態庫是不是就沒有他存在的意義呢?不見得,有人舉了這麼乙個例子:如果你用libpcap庫編了乙個程式,要給被人執行,而他的系統上沒有裝pcap庫,該怎麼解決呢?最簡單的辦法就是編譯該程式時把所有要鏈結的庫都鏈結它們的靜態庫,這樣,就可以在別人的系統上直接執行該程式了。雖然現在小烏還沒有完全理解。。。但是,存在即合理。

在windows系統下的執行檔案格式是pe格式,動態庫需要乙個dllmain函式作為初始化的人口,通常在匯出函式的宣告時需要有_declspec(dllexport)關鍵字。linux下的gcc編譯的執行檔案預設是elf格式,不需要初始化入口,亦不需要到函式做特別宣告,編寫比較方便。

說說linux下生成動/靜態鏈結庫,下面是小烏的乙個makefile檔案:

#makefile for libmy.so

libwuxian.so : getdate.o gettime.o

gcc -shared -o libwuxian.so getdate.o gettime.o

rm -f *.o

getdate.o : datetime.h

gcc -c getdate.c

gettime.o : datetime.h

gcc -c gettime.c

別被弄蒙了,這是小烏拿來練習的makefile檔案。最重要的一句話gcc -shared -o libwuxian.so getdate.o gettime.o,在shell下其實也就一句話:gcc -shared -o libwuxian.so getdate.c gettime.c,-shared說明生成的是動態鏈結庫,-o後面接生成的動態鏈結庫檔名,必須以lib打頭,.so或者.so.x結尾,x為版本號。關於makefile檔案的寫法,請看:makefile的傻瓜寫法。

對於靜態庫,則應該如下:

gcc -c xx.c

gcc -c ll.c

ar cqs libwx.a xx.o ll.o 或者ar r libwx.a xx.o ll.o

xx.c為原始檔,xx.o為目標檔案,ar cqs libwx.so xx.o ll.o是將目標檔案xx.o及ll.o鏈結為libwx.so,靜態庫名必須以lib打頭,.a結尾。

再說說動/靜態鏈結庫的使用。靜態庫是在編譯時簡單的將被用到的目標**加入到可執行程式,所以我們先說它的使用:

# gcc -c main.c -o main.o

# gcc main.o -o qqq -l. -lwx

使用gcc編譯,假設我們這裡所有的檔案都儲存在同乙個目錄下,第一句是將main.c編譯成目標檔案,第二句則是將目標檔案libwx.a和main.o鏈結到可執行程式中。

動態庫的使用則分為顯式呼叫和隱式呼叫,顯式呼叫需要了解以下幾個函式:

const char *dlerror(void);

當動態鏈結庫操作函式執行失敗時,dlerror可以返回出錯資訊,為null時表示操作函式執行成功。

void *dlopen (const char *filename, int flag);

成功則返回為void*的控制代碼。flag可以為rtld_lazy(表明在動態鏈結庫的函式**執行時解決);rtld_now(表明在dlopen返回前就解決所有未定義的符號,一旦未解決,dlopen將返回錯誤)。filename為動態庫路徑。

void *dlsym(void *handle, char *symbol);

dlsym根據動態鏈結庫操作控制代碼(handle)與符號(實際上就是欲呼叫的函式名),返回符號對應的函式的執行**位址。由此位址,可以帶引數執行相應的函式。

int dlclose (void *handle);

引數為動態鏈結庫的控制代碼。

顯式呼叫動態鏈結庫必須包含動態鏈結庫功能介面dlfcn.h(包含dl系列函式的宣告)和被調函式的宣告。看起來還比較簡單,但是當你對動態鏈結庫函式使用比較頻繁的時候,你就知道他的麻煩了,所以,不推崇。

隱式呼叫。所謂隱式呼叫,就是呼叫的時候直接使用動態庫中的函式,並不區別對待。但是在隱式呼叫的時候必須要讓程式能找到你所呼叫的函式的所屬動態庫。我們先來建立乙個感性認識:

# more /etc/ld.so.conf 你會看到以下內容:

/usr/kerberos/lib

/usr/x11r6/lib

/usr/lib/sane

/usr/lib/qt-3.1/lib

/usr/lib/mysql

/usr/lib/qt2/lib

/usr/local/lib

/usr/local/berkeleydb.4.3/lib

ld.so.conf是系統對動態鏈結庫進行查詢的路徑配置檔案,也就是說該檔案是系統鏈結工具/usr/bin/ld查詢動態鏈結庫的地圖,所以,要達到我們的目的有以下幾種方法:

1. 將自己的動態鏈結庫檔案拷到以上路徑的目錄下。

# cp libwx.so.1 /usr/local/lib

2. 將自己動態鏈結庫檔案的路徑加入到該檔案中。

要麼# vi /etc/ld.so.conf, 然後加入自己的路徑

要麼# pwd >>/etc/ld.so.conf

注意:千萬不要將》寫成》,前者是新增,後者是覆蓋,不相信你自己玩玩看。

3. 把當前路徑加入環境變數ld_library_path,其實就是/usr/bin/ld的環境變數。

# export ld_library_path=.:$ld_library_path

編譯的時候:

# gcc -o qqq main.c libmy.so.1

如果沒有讓/usr/bin/ld知道你的動態鏈結庫在哪,編譯的時候就要告訴它:

# gcc -o qqq main.c /root/wx/libmy.so.1

或者:# gcc -l/root/wx -o qqq main.c libmy.so.1

-l指定動態鏈結庫所在的目錄,有時候用gcc還會碰到-i,-l,他們分別指定標頭檔案的目錄和所鏈結的動態鏈結庫。

另外說乙個shell命令:

# ldd qqq

用來檢視可執行檔案qqq的動態鏈結庫的依賴關係。

建立共享庫的過程如下所述:

1。編譯目標檔案時使用gcc的 -fpic選項,這能產生於位置無關的**並能載入到任何位址。

2。使用gcc的 -shared 和 -soname選項。

3。使用gcc的-wl選項把引數傳遞給鏈結器ld。 

4。使用gcc的-l選項顯示地鏈結c庫,以保證可以得到所需的啟動**(startup)**,從而避免程式在使用不同的,可能是

不相容版本的c庫的系統上不能啟動執行。

<------makefile----->

cc=gcc

cflags = -g -o2 -wall

lib_name=libtest.so

lib_ver=1.0.0

objs=test1.o test2.o

all:$(objs)

$(cc) $(cflags) -shared -wl,-soname,$(lib_name) -o $(lib_name).$(lib_ver) $(objs) -lc

%.o: %.c

%(cc) $(cflags) -fpic -c $< -o $@

<------eof--------->

linux動 靜態庫的生成和使用

在小烏的眼裡,庫檔案就是資源檔案,也沒有什麼難以理解的 可是如果真要問得深入一點 動態鏈結庫和靜態鏈結庫有什麼區別?怎麼做乙個動態鏈結庫?怎麼生成靜態 動態鏈結庫?什麼叫顯示 隱示呼叫?小烏就鬱悶了,所以今天決定要拍死這些問題。window下面的動 靜態鏈結庫檔名分別為 dll和.lib linux...

LINUX下生成動 靜態庫檔案

1.生成.so檔案的命令 linux系統中的動態鏈結庫檔案 a g test a.cpp test b.cpp fpic shared o libtest.so g test.cpp o test l.ltestb 生成 gcc fpic shared port.cpp print.cpp o pr...

基礎I O口和動靜態庫的生成

math.h 1 ifndef mymath h 2 define mymath h 3 int add int x,int y 4 5 int sub int x,int y 6 7 int mul int x,int y 8 9 int div int x,int y 10 endif myma...