1、靜態(tài)庫(kù)和共享庫(kù)?
靜態(tài)庫(kù)和共享庫(kù)(動(dòng)態(tài)庫(kù)),二者的不同點(diǎn)在于代碼被載入的時(shí)刻不同。?
靜態(tài)庫(kù)的代碼在編譯過(guò)程中已經(jīng)被載入可執(zhí)行程序,因此體積較大。?
共享庫(kù)的代碼是在可執(zhí)行程序運(yùn)行時(shí)才載入內(nèi)存的,在編譯過(guò)程中僅簡(jiǎn)單的引用,因此代碼體積較小。
靜態(tài)鏈接庫(kù)和動(dòng)態(tài)鏈接庫(kù)的區(qū)別在于,主程序在運(yùn)行前,靜態(tài)鏈接庫(kù)的鏈接固定寫(xiě)入在程序中,而動(dòng)態(tài)鏈接庫(kù)則是在每次程序運(yùn)行再加載鏈接。
2、庫(kù)存在的意義?
庫(kù)是別人寫(xiě)好的現(xiàn)有的,成熟的,可以復(fù)用的代碼,你可以使用但要記得遵守許可協(xié)議。?
現(xiàn)實(shí)中每個(gè)程序都要依賴(lài)很多基礎(chǔ)的底層庫(kù),不可能每個(gè)人的代碼都從零開(kāi)始,因此庫(kù)的存在意義非同尋常。?
共享庫(kù)的好處是,不同的應(yīng)用程序如果調(diào)用相同的庫(kù),那么在內(nèi)存里只需要有一份該共享庫(kù)的實(shí)例。
3.靜態(tài)庫(kù)?
Step 1.由源文件編譯生成一堆.o,每個(gè).o里都包含這個(gè)編譯單元的符號(hào)表?
Step 2.ar命令將很多.o轉(zhuǎn)換成.a,成為靜態(tài)庫(kù)
靜態(tài)鏈接庫(kù) libcool.a 遵從 GNU/Linux 規(guī)定的靜態(tài)鏈接庫(kù)命名規(guī)范,必須是”libyour_library_name.a”
動(dòng)態(tài)庫(kù)的后綴是.so,它由gcc加特定參數(shù)編譯產(chǎn)生。?
4、動(dòng)態(tài)庫(kù)
在 GNU/Linux 中動(dòng)態(tài)鏈接文件,必需通過(guò)鏈接器 ld 生成。假設(shè)我們有 hot.c other.c 等文件要生成動(dòng)態(tài)鏈接庫(kù) libhot.so 。首先使用如下指令得到相應(yīng)的 object 文件 hot.o 和 other.o?
gcc -fPIC -c hot.c?
gcc -fPIC -c other.c?
參數(shù) -fPIC 指定生成的 object 文件為位置無(wú)關(guān)代碼(position-independence code),只有 PIC 可以被用作生成動(dòng)態(tài)鏈接庫(kù)。然后使用如下指令得到動(dòng)態(tài)庫(kù):
ld -Bshared -o libhot.so hot.o other.o?
或者可以使用編譯器的ld wrapper:?
gcc -shared -o libhot.so hot.o other.o?
也可以使用編譯器直接生成動(dòng)態(tài)庫(kù):?
gcc -fPIC -shared -o libhot.so hot.c other.c?
這里選項(xiàng) -shared 指示目標(biāo)文件的類(lèi)型是動(dòng)態(tài)鏈接庫(kù),動(dòng)態(tài)庫(kù)的命名規(guī)范是”libyour_library_name.so”
linux操作系統(tǒng)中,?
1.和靜態(tài)庫(kù)類(lèi)似,動(dòng)態(tài)庫(kù)文件也是一些目標(biāo)文件(后綴名為.o)的集合體而已。?
2.動(dòng)態(tài)庫(kù)的后綴名是.so,對(duì)應(yīng)于windows操作系統(tǒng)的后綴名為.dll的動(dòng)態(tài)庫(kù)。?
3.可以使用gcc命令來(lái)創(chuàng)建一個(gè)動(dòng)態(tài)庫(kù)文件。?
來(lái)看一個(gè)實(shí)例,和靜態(tài)庫(kù)的代碼實(shí)際是一樣的。先看看可以編譯成庫(kù)文件的源文件中的代碼:
/* test.c */ int f() { return 3; }
1
2
3
4
5
代碼非常簡(jiǎn)單。我們敲入下列命令:
gcc -c -fPIC test.cgcc -shared -fPIC -o libtest.so test.o
1
2
會(huì)在當(dāng)前目錄下生成一個(gè)libtest.so動(dòng)態(tài)庫(kù)文件。再看如何使用這個(gè)庫(kù)??慈缦麓a:
/* app.c */ #include extern int f(); int main() { printf(“return value is %d ”,f()); return 0; }
1
2
3
4
5
6
7
8
敲入如下命令:
gcc –c app.cgcc -o app app.o -L. –ltest
1
2
敲命令的時(shí)候要記得將libtest.a文件和生成的app.o文件放在同一個(gè)目錄(即當(dāng)前目錄)下。這樣,敲入命令后,會(huì)在當(dāng)前目錄下生成一個(gè)名為app的可執(zhí)行文件。但是當(dāng)我們執(zhí)行./app命令,來(lái)執(zhí)行這個(gè)可執(zhí)行文件時(shí),卻提示如下錯(cuò)誤:
這就奇怪了,libtest.so文件明明就在當(dāng)前目錄下,為什么會(huì)提示找不到呢?? 原來(lái)linux和windows的機(jī)制是不同的,它不會(huì)在當(dāng)前目錄下尋找動(dòng)態(tài)連接庫(kù)文件,它只會(huì)在標(biāo)準(zhǔn)路徑下尋找。(The system searches only /lib and /usr/lib, by default.)。我們可以使用一個(gè)命令,使得操作系統(tǒng)去我們指定的路徑下面去尋找。假設(shè)libtest.so文件所在的目錄是/root/Desktop/aabb,那么執(zhí)行命令
export LD_LIBRARY_PATH=/root/Desktop/aabb
1
后,再執(zhí)行./app,我們發(fā)現(xiàn),程序就正常運(yùn)行了。
在加載動(dòng)態(tài)鏈接庫(kù)的時(shí)候,有可能會(huì)遇到加載不到的錯(cuò)誤,原因在于系統(tǒng)默認(rèn)加載的動(dòng)態(tài)鏈接庫(kù)路徑里沒(méi)有找到你的動(dòng)態(tài)庫(kù),有三種解決方法:
1.在執(zhí)行g(shù)cc main.c -L. -ltest -o main 前,執(zhí)行 export LD_LIBRARY_PATH=$(pwd)
2.將其添加到/etc/ld.so.cache文件中。將你so所在的目錄寫(xiě)到/etc/ld.so.conf文件里,然后執(zhí)行l(wèi)dconfig該命令會(huì)重建/etc/ld.so.cache文件。
3.將你的so放在/etc/ld.so.conf里的路徑位置里。
Linux下的dlopen、dlsym、dlclose 相當(dāng)于windows平臺(tái)的LoadLibrary、GetProcAddress 、FreeLibrary,可以在運(yùn)行時(shí)動(dòng)態(tài)加載動(dòng)態(tài)庫(kù),使用其中的導(dǎo)出函數(shù)。但是局限在于,這樣僅僅能夠?qū)С鋈趾瘮?shù),而不能導(dǎo)出類(lèi)的方法。所以一般動(dòng)態(tài)庫(kù)導(dǎo)出C++類(lèi)實(shí)現(xiàn)的功能時(shí)都會(huì)設(shè)計(jì)一大堆的全局函數(shù)來(lái)包裝一下。? 包含頭文件:
#include dlfcn.h : Linux動(dòng)態(tài)庫(kù)的顯式調(diào)用
1
函數(shù)
void * dlopen( const char * pathname, int mode );
1
函數(shù)描述:? 在dlopen的()函數(shù)以指定模式打開(kāi)指定的動(dòng)態(tài)連接庫(kù)文件,并返回一個(gè)句柄給調(diào)用進(jìn)程。使用dlclose()來(lái)卸載打開(kāi)的庫(kù)。? mode:分為這兩種? RTLD_LAZY 暫緩決定,等有需要時(shí)再解出符號(hào)? RTLD_NOW 立即決定,返回前解除所有未決定的符號(hào)。
dlerror? 函數(shù)定義:
void*dlsym(void* handle,const char* symbol)
1
函數(shù)描述:? dlsym根據(jù)動(dòng)態(tài)鏈接庫(kù)操作句柄(handle)與符號(hào)(symbol),返回符號(hào)對(duì)應(yīng)的地址。使用這個(gè)函數(shù)不但可以獲取函數(shù)地址,也可以獲取變量地址。? dlclose
dlopen以指定模式打開(kāi)指定的動(dòng)態(tài)連接庫(kù)文件,并返回一個(gè)句柄給調(diào)用進(jìn)程,dlerror返回出現(xiàn)的錯(cuò)誤,dlsym通過(guò)句柄和連接符名稱(chēng)獲取函數(shù)名或者變量名,dlclose來(lái)卸載打開(kāi)的庫(kù)。 dlopen打開(kāi)模式如下:
RTLD_LAZY 暫緩決定,等有需要時(shí)再解出符號(hào)? RTLD_NOW 立即決定,返回前解除所有未決定的符號(hào)。? 生產(chǎn)動(dòng)態(tài)鏈接庫(kù)
編譯參數(shù) gcc -fPIC -shared
使用so文件的編譯參數(shù)? 編譯選項(xiàng)如下:
gcc -rdynamic -o main main.c -ldl
1
選項(xiàng) -rdynamic 用來(lái)通知鏈接器將所有符號(hào)添加到動(dòng)態(tài)符號(hào)表中? (目的是能夠通過(guò)使用 dlopen 來(lái)實(shí)現(xiàn)向后跟蹤)比如日志系統(tǒng),主程序里使用一套日志系統(tǒng),dlopen方式打開(kāi)的libso里無(wú)法使用。編譯時(shí)加上這個(gè)參數(shù),不需要增加任何代碼就可以使代碼通用。? 使用-ldl選項(xiàng)指明生成的對(duì)象模塊需要使用共享庫(kù)
?
評(píng)論