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