静态库和共享库制作
1靜態(tài)庫(kù)和共享庫(kù)
*本節(jié)就如何創(chuàng)建和使用程序庫(kù)進(jìn)行論述。所謂“程序庫(kù)”,簡(jiǎn)單說(shuō),就是包含了數(shù)據(jù)
和執(zhí)行碼的文件。其不能單獨(dú)執(zhí)行,可以作為其它執(zhí)行程序的一部分來(lái)完成某些功能。庫(kù)的
存在,可以使得程序模塊化,可以加快程序的再編譯,可以實(shí)現(xiàn)代碼重用,可以使得程序便
于升級(jí)。程序庫(kù)可分靜態(tài)庫(kù)(static library)和共享庫(kù)(shared object)。
?
A:靜態(tài)庫(kù)
是在可執(zhí)行程序運(yùn)行前就已經(jīng)加入到執(zhí)行碼中,成為執(zhí)行程序的一部分;共享庫(kù),是在
執(zhí)行程序啟動(dòng)時(shí)加載到執(zhí)行程序中,可以被多個(gè)執(zhí)行程序共享使用。
建議庫(kù)開發(fā)人員創(chuàng)建共享庫(kù),比較明顯的優(yōu)勢(shì)在于庫(kù)是獨(dú)立的,便于維護(hù)和更新;而靜
態(tài)庫(kù)的更新比較麻煩,一般不做推薦。然而,它們又各有優(yōu)點(diǎn),后面會(huì)講到。
節(jié)所講述的執(zhí)行程序和庫(kù)都采用ELF(Executable and Linking Format)格式,盡管GNU
GCC工具可以處理其它格式,但不在本節(jié)的討論范圍。
靜態(tài)庫(kù)可以認(rèn)為是一些目標(biāo)代碼的集合。按照習(xí)慣,一般以“.a”做為文件后綴名。使
用ar(archiver)命令可以創(chuàng)建靜態(tài)庫(kù)。因?yàn)楣蚕韼?kù)有著更大的優(yōu)勢(shì),靜態(tài)庫(kù)已經(jīng)不經(jīng)常使
用。但靜態(tài)庫(kù)使用簡(jiǎn)單,仍有使用的余地,并會(huì)一直存在。有些Unix系統(tǒng),如Solaris 10,
已經(jīng)基本廢棄了靜態(tài)庫(kù)。
靜態(tài)庫(kù)在應(yīng)用程序生成時(shí),可以不必再編譯,節(jié)省再編譯時(shí)間。但在編譯器越來(lái)越快的
今天,這一點(diǎn)似乎已不重要。如果其他開發(fā)人員要使用你的程序,而你又不想給其源碼,提
供靜態(tài)庫(kù)是一種選擇。從理論上講,應(yīng)用程序使用了靜態(tài)庫(kù),要比使用動(dòng)態(tài)加載庫(kù)速度快
1-5%,但實(shí)際上可能并非如此。由此看來(lái),除了使用方便外,靜態(tài)庫(kù)可能并非一種好的選
擇。
要?jiǎng)?chuàng)建一個(gè)靜態(tài)庫(kù),或要將目標(biāo)代碼加入到已經(jīng)存在的靜態(tài)庫(kù)中,可以使用以下命令:
?
ar rcs libmylib.a file1.o
?
file2.o以上表示要把目標(biāo)碼file1.o和file2.o加入到靜態(tài)庫(kù)libmylib.a中(ar的參數(shù)
r)。若libmylib.a不存在,會(huì)自動(dòng)創(chuàng)建(ar的參數(shù)c)。然后更新.a文件的索引,使之包含新
加入的.o文件的內(nèi)容(ar的參數(shù)s)。
靜態(tài)庫(kù)創(chuàng)建成功后,需要鏈接到應(yīng)用程序中使用。使用gcc的-l選項(xiàng)來(lái)指定靜態(tài)庫(kù),使
用-L參數(shù)來(lái)指定庫(kù)文件的搜索路徑。比如上述例子應(yīng)指定-lmylib,所有庫(kù)文件名都以lib開
頭,開頭的lib在指定參數(shù)時(shí)應(yīng)省略。-l和-L之后都直接帶參數(shù)而不跟空格。
在使用gcc時(shí),要注意其參數(shù)的順序。-l是鏈接器選項(xiàng),一定要放在被編譯的文件名稱
之后;若放在文件名稱之前則會(huì)連接失敗,并會(huì)出現(xiàn)莫名其妙的錯(cuò)誤。這一點(diǎn)切記。
?
B:共享庫(kù)
共享庫(kù)的創(chuàng)建比較簡(jiǎn)單,基本有兩步。首先使用-fPIC或-fpic創(chuàng)建目標(biāo)文件,PIC或
pic表示位置無(wú)關(guān)代碼,然后就可以使用以下格式創(chuàng)建共享庫(kù)了: gcc -share -Wl,-
soname,your_soname -o library_namefile_list library_list 下面是使用a.c和b.c創(chuàng)建
庫(kù)的示例:
?
相關(guān)命令:
gcc –fPIC –c XX.c
gcc –fpic –c XX.c
gcc -shared -Wl,-soname,libmyab.so.1-o libmyab.so.1.0.1 a.o b.o
?
libmyab.so.1稱之為soname,
libmyab.so.1.0.1稱之為realname
libmyab.so? 稱之為linker name
?
按照共享庫(kù)的命名慣例,每個(gè)共享庫(kù)有三個(gè)文件名:real name、soname和linker
name。真正的庫(kù)文件(而不是符號(hào)鏈接)的名字是realname,包含完整的共享庫(kù)版本號(hào)。
soname是一個(gè)符號(hào)鏈接的名字,只包含共享庫(kù)的主版本號(hào),主版本號(hào)一致即可保證庫(kù)函
數(shù)的接口一致,因此應(yīng)用程序的.dynamic段只記錄共享庫(kù)的soname,只要soname一致,這個(gè)
共享庫(kù)就可以用。如libmyab.so.1和libmyab.so.2是兩個(gè)主版本號(hào)不同的libmyab,有些應(yīng)
用程序依賴于libmyab.so.1,有些應(yīng)用程序依賴于libmyab.so.2,但對(duì)于依賴libmyab.so.1
的應(yīng)用程序來(lái)說(shuō),真正的庫(kù)文件不管是libmyab.so.1.10還是libmyab.so.1.11都可以用,所
以使用共享庫(kù)可以很方便地升級(jí)庫(kù)文件而不需要重新編譯應(yīng)用程序,這是靜態(tài)庫(kù)所沒有的優(yōu)點(diǎn)。
注意libc的版本編號(hào)有一點(diǎn)特殊,libc-2.8.90.so的主版本號(hào)是6而不是2或2.8。
linker name僅在編譯鏈接時(shí)使用,gcc的-L選項(xiàng)應(yīng)該指定linkername所在的目錄。有
的linker name是庫(kù)文件的一個(gè)符號(hào)鏈接,有的linker name是一段鏈接腳本。例如上面的
libc.so就是一個(gè)linkername,它是一段鏈接腳本:
?
C:共享庫(kù)加載
在所有基于GNUglibc的系統(tǒng)中,在啟動(dòng)一個(gè)ELF二進(jìn)制執(zhí)行程序時(shí),一個(gè)特殊的
程序“程序裝載器”會(huì)被自動(dòng)裝載并運(yùn)行。在linux中,這個(gè)程序裝載器就是/lib/ldlinux.
so.X(X是版本號(hào))。它會(huì)查找并裝載應(yīng)用程序所依賴的所有共享庫(kù)。被搜索的目錄保存在/etc/ld.so.conf文件中。當(dāng)然,如果程序的每次啟動(dòng),都要去搜索一番,勢(shì)必效率不
堪忍受。Linux系統(tǒng)已經(jīng)考慮這一點(diǎn),對(duì)共享庫(kù)采用了緩存管理。ldconfig就是實(shí)現(xiàn)這一功
能的工具,其缺省讀取/etc/ld.so.conf文件,對(duì)所有共享庫(kù)按照一定規(guī)范建立符號(hào)連接,
然后將信息寫入/etc/ld.so.cache。/etc/ld.so.cache的存在大大加快了程序的啟動(dòng)速
度。
?
D:案例說(shuō)明:
D1:創(chuàng)建一個(gè)目錄,mycal
mkdir mycal
?D2:創(chuàng)建4個(gè)c文件盒1個(gè).h,分別實(shí)現(xiàn)加減乘除
?add.c
?
?sub.c
mul.c
dive.c
common.h
??編寫main.c
| #include <stdio.h> #include "common.h" ? int main(void) { ??? printf("%d", add(5, 4)); ??? return 0; } |
D3制作靜態(tài)庫(kù)(加上-fPIC后生成的目標(biāo)文件和位置無(wú)關(guān),注意要加上這個(gè))
查看靜態(tài)庫(kù)信息:
使用靜態(tài)庫(kù)(程序扔到任何電腦都可以運(yùn)行,因?yàn)殪o態(tài)庫(kù)相當(dāng)于包含到了靜態(tài)庫(kù)中):
gcc -Isrc main.c libmycal.a –o app(加-Isrc是為類引用common.h)
ldd app命令檢測(cè)的是共享庫(kù),不檢測(cè)靜態(tài)庫(kù)
上面的過(guò)程相當(dāng)于libmycal.a和main.c進(jìn)行組合,生成app
??D4制作共享庫(kù),
??移動(dòng)目錄如下結(jié)構(gòu):
?
這時(shí)候生成了realname:??? libmycal.so.1.10
D5設(shè)置共享庫(kù)加載路徑
??打開共享庫(kù)路徑配置文件
??sudo vi /etc/ld.so.conf
??最后一行添加mycal路徑,截圖如下,若不配置下面的信息,它后后面的gcc執(zhí)行的命令和ldd命令回報(bào)沒有找到庫(kù)的提示信息。(下面配置告訴庫(kù)所在的位置)
?
sudo ldconfig –v(輸入后輸出一堆結(jié)果,如果還是發(fā)現(xiàn)沒有生成libmycal.so.1,這時(shí)候要去除緩存文件/etc/ld.so.cache? 命令是:sudo rm –rf/etc/ld.so.cache
gcc main.c libmycal.so.1.10 -o app
?
ldd app查看程序運(yùn)行的時(shí)候的依賴信息
如果用ldd app查看還是沒有看到依賴,要去掉依賴文件,要?jiǎng)h除的緩存文件是:/etc/ld.so.cache
注意:共享庫(kù)和main.c共同使用的時(shí)候,在這個(gè)過(guò)程中相當(dāng)于生成了main.o,符號(hào)記錄表。app運(yùn)行的時(shí)候依賴共享庫(kù)版本。
?
?
?
?
總結(jié)
- 上一篇: 生活常识:如何正确烤炸鱿鱼圈?
- 下一篇: 2通过程序获得环境变量,getenv()