UNIX再学习 -- 静态库与共享库
生活随笔
收集整理的這篇文章主要介紹了
UNIX再学习 -- 静态库与共享库
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一、庫
本質(zhì)上來說庫是一種可執(zhí)行代碼的二進(jìn)制形式,可以被操作系統(tǒng)載入內(nèi)存執(zhí)行。由于Windows和linux本質(zhì)不同,因此二者庫的二進(jìn)制是不兼容的。庫有兩種:靜態(tài)庫(.a、.lib)和共享庫也稱動(dòng)態(tài)庫(.so、.dll)。回顧下,我們之前講gcc編譯過程可分為四個(gè)階段:預(yù)處理->>編譯->>匯編->>鏈接。而所謂的靜態(tài)、動(dòng)態(tài)就指的是鏈接階段。
注意,可執(zhí)行代碼的二進(jìn)制形式,即ELF格式。以后有時(shí)間會(huì)詳細(xì)介紹下它。
參看:可執(zhí)行文件(ELF)格式的理解
參看:C語言再學(xué)習(xí)-- readelf、objdump、nm使用詳解
二、靜態(tài)庫
1、靜態(tài)庫介紹
靜態(tài)庫指將所有相關(guān)的目標(biāo)文件打包成為一個(gè)單獨(dú)的文件,即靜態(tài)庫文件,其缺省擴(kuò)展名是 ?.a 。鏈接靜態(tài)庫就是將庫中被調(diào)用的代碼復(fù)制到調(diào)用模塊中。靜態(tài)庫占用空間大,庫中代碼一旦修改必須重新鏈接。使用靜態(tài)庫的代碼在運(yùn)行時(shí)無需依賴庫,且執(zhí)行效率高。 靜態(tài)庫命名規(guī)范,必須是"lib[your_library_name].a":lib為前綴,中間是靜態(tài)庫名,擴(kuò)展名為.a。例如:libadd.a
以下源碼文件將用于下面的講解: //add.c 加法運(yùn)算函數(shù) #include "add.h" int add_int (int ia, int ib) {return ia + ib; }//add.h 頭文件 #ifndef ADD_H//防止頭文件被多次包含 #define ADD_H #include <stdio.h> //聲明一個(gè)函數(shù) int add_int(int ia,int ib); #endif//main.c 主函數(shù) #include "add.h" int main() {printf("計(jì)算兩個(gè)整數(shù)的和是:%d\n",add_int(20,40));return 0; }
2、靜態(tài)庫的創(chuàng)建和使用
(1)只編譯不鏈接,生成目標(biāo)文件
gcc -c add.c main.c 生成目標(biāo)文件 add.o main.o(2)使用 ar -r 命令創(chuàng)建靜態(tài)庫文件 ?(創(chuàng)建)
ar -r lib庫名 .a 目標(biāo)文件ar -r libadd.a add.o 創(chuàng)建靜態(tài)庫文件 libadd.a
(3)鏈接測試程序和庫文件 ?(使用)
主要有三種方法: 1)直接連接 gcc main.o libadd.a -o add 生成可執(zhí)行文件 add2)通過編譯器選項(xiàng)進(jìn)行間接鏈接 (重點(diǎn)) gcc/cc main.o -l 庫名 -L 庫文件所在的路徑gcc main.o -l add -L . -o add 生成可執(zhí)行文件 add3)配置環(huán)境變量 LIBRARY_PSTH 進(jìn)行連接 export LIBRARY_PATH=$LIBRARY_PATH:.
gcc/cc main.o -l 庫名?
未配置環(huán)境變量之前編譯錯(cuò)誤: gcc main.o -l add /usr/bin/ld: cannot find -ladd collect2: ld 返回 1 配置環(huán)境變量 export LIBRARY_PATH=$LIBRARY_PATH:. gcc main.o -l add -o add 生成可執(zhí)行文件 add
3、講解
(1)首先gcc編譯過程,之前有講參看:C語言再學(xué)習(xí) -- GCC編譯過程?在此就不重復(fù)了。不過需要知道為什么只編譯不鏈接,生成目標(biāo)文件。前面已經(jīng)講到了,gcc編譯過程可分為四個(gè)階段:預(yù)處理->>編譯->>匯編->>鏈接。而所謂的靜態(tài)、動(dòng)態(tài)就指的是鏈接階段。所以它需要在匯編階段生成目標(biāo)文件,然后鏈接靜態(tài)庫/動(dòng)態(tài)庫生成可執(zhí)行文件。 (2)ar命令 感興趣的可以 ?man ar The GNU ar program creates, modifies, and extracts from archives. An archive is a single file holding a collection of other filesin a structure that makes it possible to retrieve the original individual files (called members of the archive). The original files' contents, mode (permissions), timestamp, owner, and group are preserved in the archive, and can be restored onextraction. ar [選項(xiàng)] <靜態(tài)庫文件> <目標(biāo)文件列表> -r ? ? 將目標(biāo)文件插入到靜態(tài)庫中,已存在則更新 -q ? ?將目標(biāo)文件追加到靜態(tài)庫尾 -d ? ?從靜態(tài)庫中刪除目標(biāo)文件 -t ? ? 列表顯示靜態(tài)庫中的目標(biāo)文件 -x ? ? 將靜態(tài)庫展開為目標(biāo)文件 (3)鏈接 gcc編譯器,連接程序選項(xiàng)說明:-L dir:將dir所指出的目錄加到“函數(shù)庫搜索列表”中,dir 為庫文件所在的路徑
-llib: 鏈接lib庫,lib 為庫名
-I name: 連接時(shí),加載名字為name的函數(shù)庫。該庫位于系統(tǒng)預(yù)設(shè)的目錄或者由-L選項(xiàng)確定的目錄下。實(shí)際的庫名是libname(后綴為.a或.so) (4)配置環(huán)境變量 上篇文章已經(jīng)專門講了,參看:Unix再學(xué)習(xí) -- 環(huán)境變量?需要注意的是,靜態(tài)庫屬于編譯鏈接階段,所以如此配置?export LIBRARY_PATH=$LIBRARY_PATH:. ?而它的意思是,靜態(tài)庫文件在當(dāng)前目錄下查找,配置的環(huán)境變量對當(dāng)前用戶臨時(shí)有效。
三、共享庫
1、共享庫介紹
共享庫和靜態(tài)庫最大的不同就是,鏈接共享庫并不需要將庫中被調(diào)用的代碼復(fù)制到調(diào)用模塊中,相反被嵌入到調(diào)用模塊中的僅僅是被調(diào)用代碼在共享庫中的相對地址。如果共享庫中的代碼同時(shí)為多個(gè)進(jìn)程所用,共享庫的實(shí)例在整個(gè)內(nèi)存空間中僅需一份,這正是共享的意義所在。共享庫占用空間小,即使修改了庫中的代碼,只要接口保持不變,無需重新鏈接。使用共享庫的代碼在運(yùn)行時(shí)需要依賴庫,執(zhí)行效率略低。而共享庫的缺省擴(kuò)展名是: .so 共享庫命名規(guī)范,必須是"lib[your_library_name].so":lib為前綴,中間是共享庫名,擴(kuò)展名為 .so例如:libadd.so
2、共享庫的創(chuàng)建和使用
(1)只編譯不鏈接,生成目標(biāo)文件
gcc -c -fpic add.c main.c 生成目標(biāo)文件 add.o main.o(2)創(chuàng)建共享庫文件 (創(chuàng)建)
gcc/cc -shared xxx.o -o lib庫名.sogcc -shared add.o -o libadd.so 生成共享庫文件 libadd.so
(3)鏈接測試程序和庫文件 (使用)
主要有三種方法:1)直接鏈接gcc main.o libadd.so -o add 生成可執(zhí)行文件 add2)通過編譯器選項(xiàng)進(jìn)行間接鏈接 (重點(diǎn))gcc/cc main.o -l 庫名 -L 庫文件所在的路徑gcc main.o -l add -L . -o add 生成可執(zhí)行文件 add3)配置環(huán)境變量?LIBRARY_PSTH 和?LD_LIBRARY_PSTH 進(jìn)行連接、運(yùn)行export LIBRARY_PATH=$LIBRARY_PATH:.
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
gcc/cc main.o -l 庫名未配置環(huán)境變量 LIBRARY_PATH 之前編譯錯(cuò)誤: gcc main.o -l add /usr/bin/ld: cannot find -ladd collect2: ld 返回 1 未配置環(huán)境變量 LD_LIBRARY_PATH 之前運(yùn)行錯(cuò)誤: ./add: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory 配置環(huán)境變量 export LIBRARY_PATH=$LIBRARY_PATH:. gcc main.o -l add -o add 生成可執(zhí)行文件 add 配置環(huán)境變量 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. 運(yùn)行 ./add 成功
3、講解
(1)gcc編譯過程,同靜態(tài)庫一樣。不過gcc編譯里面使用了選項(xiàng) -fpic 需要講一下。 PIC (Position Independent Code,告訴編譯器產(chǎn)生與位置無關(guān)代碼) 調(diào)用代碼通過相對地址標(biāo)識被調(diào)用代碼的位置,模塊中的指令與該模塊被加載到內(nèi)存中的位置無關(guān)。 (通俗點(diǎn)就是在可執(zhí)行程序裝載它們的時(shí)候,它們可以放在可執(zhí)行程序的內(nèi)存里的任何地方。) -fPIC:大模式,生成代碼比較大,運(yùn)行速度比較慢,所有平臺(tái)都支持。 -fpic :小模式,生成代碼比較小,運(yùn)行速度比較快,僅部分平臺(tái)支持。 我們可以比較下未使用 -fpic 和使用后生成的目標(biāo)文件大小。可以看出,使用 fpic 生成的目標(biāo)文件,多了.group 和 .text? 詳細(xì)可參看:GCC參數(shù)的官方介紹 -fpic Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine. Such code accesses all constant addresses through a global offset table (GOT). The dynamic loader resolves the GOT entries when the program starts (the dynamic loader is not part of GCC; it is part of the operating system). If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead. (These maximums are 8k on the SPARC, 28k on AArch64 and 32k on the m68k and RS/6000. The x86 has no such limit.)Position-independent code requires special support, and therefore works only on certain machines. For the x86, GCC supports PIC for System V but not for the Sun 386i. Code generated for the IBM RS/6000 is always position-independent.When this flag is set, the macros __pic__ and __PIC__ are defined to 1.-fPIC If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any limit on the size of the global offset table. This option makes a difference on AArch64, m68k, PowerPC and SPARC.Position-independent code requires special support, and therefore works only on certain machines.When this flag is set, the macros __pic__ and __PIC__ are defined to 2.(2)gcc編譯 -shared選項(xiàng) 產(chǎn)生共享庫文件? -shared Produce a shared object which can then be linked with other objects to form an executable. Not all systems support this option.(3)配置環(huán)境變量
通過?未配置環(huán)境變量 LIBRARY_PATH 之前編譯錯(cuò)誤、未配置環(huán)境變量 LD_LIBRARY_PATH 之前運(yùn)行錯(cuò)誤 可以明顯驗(yàn)證,它們的作用了。 LIBRARY_PATH:Linux gcc編譯鏈接時(shí)的共享庫搜索路徑。
LIBRARY_PATH:執(zhí)行二進(jìn)制文件時(shí)的共享庫搜索路徑。
在可執(zhí)行程序的鏈接階段,并不將所調(diào)用函數(shù)的二進(jìn)制代碼復(fù)制到可執(zhí)行程序中,而只是將該函數(shù)在共享庫中的地址嵌入到調(diào)用模塊中,因此運(yùn)行時(shí)需要依賴共享庫。 (4)gcc缺省鏈接共享庫,可通過 -static 選項(xiàng)強(qiáng)制鏈接靜態(tài)庫。 參看:GCC -static常見問題
-static On systems that support dynamic linking, this prevents linking with the shared libraries. On other systems, this option has no effect.在GCC中,會(huì)優(yōu)先使用shard library. 為了確保使用的是靜態(tài)庫,則使用此選項(xiàng)。例如:
鏈接時(shí)有-static選項(xiàng),卻鏈接了共享庫,則會(huì)報(bào)錯(cuò) # gcc -static main.o libadd.so -o add /usr/bin/ld: attempted static link of dynamic object `libadd.so' collect2: ld 返回 1
四、靜態(tài)庫與共享庫比較
(1)靜態(tài)庫在程序編譯時(shí)會(huì)被連接到目標(biāo)代碼中,程序運(yùn)行時(shí)將不再需要該靜態(tài)庫。當(dāng)程序與靜態(tài)庫連接時(shí),庫中目標(biāo)文件所含的所有將被程序使用的函數(shù)的機(jī)器碼被copy到最終的可執(zhí)行文件中。這就會(huì)導(dǎo)致最終生成的可執(zhí)行代碼量相對變多,相當(dāng)于編譯器將代碼補(bǔ)充完整了,這樣運(yùn)行起來相對就快些。不過會(huì)有個(gè)缺點(diǎn): 占用磁盤和內(nèi)存空間。靜態(tài)庫會(huì)被添加到和它連接的每個(gè)程序中,而且這些程序運(yùn)行時(shí),都會(huì)被加載到內(nèi)存中,無形中又多消耗了更多的內(nèi)存空間。(2)動(dòng)態(tài)庫在程序編譯時(shí)并不會(huì)被連接到目標(biāo)代碼中,而是在程序運(yùn)行是才被載入,因此在程序運(yùn)行時(shí)還需要?jiǎng)討B(tài)庫存在。與共享庫連接的可執(zhí)行文件只包含它需要的函數(shù)的引用表,而不是所有的函數(shù)代碼,只有在程序執(zhí)行時(shí),那些需要的函數(shù)代碼才被拷貝到內(nèi)存中。這樣就使可執(zhí)行文件比較小,節(jié)省磁盤空間,更進(jìn)一步,操作系統(tǒng)使用虛擬內(nèi)存,使得一份共享庫駐留在內(nèi)存中被多個(gè)程序使用,也同時(shí)節(jié)約了內(nèi)存。不過由于運(yùn)行時(shí)要去鏈接庫會(huì)花費(fèi)一定的時(shí)間,執(zhí)行速度相對會(huì)慢一些。
(3)總的來說靜態(tài)庫是犧牲了空間效率,換取了時(shí)間效率,共享庫是犧牲了時(shí)間效率換取了空間效率,沒有好與壞的區(qū)別,只看具體需要了。
(4)另外,一個(gè)程序編好后,有時(shí)需要做一些修改和優(yōu)化,如果我們要修改的剛好是庫函數(shù)的話,在接口不變的前提下,使用共享庫的程序只需要將共享庫重新編譯就可以了,而使用靜態(tài)庫的程序則需要將靜態(tài)庫重新編譯好后,將程序再重新編譯一遍。例如,將 add.c改為乘法運(yùn)算://乘法運(yùn)算 #include "add.h"int add_int(int ia,int ib) {return ia*ib; } 共享庫操作是:生成目標(biāo)文件add.o: gcc -c -fpic add.c 生成共享庫文件libadd.so: gcc -shared add.o -o libadd.so 不需要再編譯生成可執(zhí)行文件 直接執(zhí)行./add 輸出結(jié)果: 計(jì)算兩個(gè)整數(shù)的和是:800 靜態(tài)庫操作是:生成目標(biāo)文件add.o: gcc -c add.c 生成靜態(tài)庫文件libadd.a: ar -r libadd.a add.o 重新編譯生成可執(zhí)行文件add: gcc main.o libadd.a -o add 執(zhí)行./add 輸出結(jié)果: 計(jì)算兩個(gè)整數(shù)的和是:800
五、動(dòng)態(tài)庫的顯式調(diào)用
參看:C++靜態(tài)庫與動(dòng)態(tài)庫#include <dlfcn.h>,提供了下面幾個(gè)接口:(1)加載共享庫?dlopenvoid * dlopen( const char * pathname, int mode )函數(shù)功能:以指定模式打開指定的動(dòng)態(tài)連接庫文件,并返回一個(gè)句柄給調(diào)用進(jìn)程。打開模式:RTLD_LAZY ?暫緩決定,等有需要時(shí)再解出符號?
RTLD_NOW 立即決定,返回前解除所有未決定的符號。?返回值:?
打開錯(cuò)誤返回NULL,成功,返回庫引用?
編譯時(shí)候要加入 -ldl (指定dl庫)?感興趣的可以 man dlopen One of the following two values must be included in flag:RTLD_LAZYPerform lazy binding. Only resolve symbols as the code that references them is executed. If the symbol is never referenced,then it is never resolved. (Lazy binding is only performed for function references; references to variables are always imme‐diately bound when the library is loaded.)RTLD_NOWIf this value is specified, or the environment variable LD_BIND_NOW is set to a nonempty string, all undefined symbols in thelibrary are resolved before dlopen() returns. If this cannot be done, an error is returned.(2)獲取函數(shù)地址 dlsymvoid* dlsym(void* handle,const char* symbol)函數(shù)功能:dlsym根據(jù)動(dòng)態(tài)鏈接庫操作句柄(handle)與符號(symbol),返回符號對應(yīng)的地址。使用這個(gè)函數(shù)不但可以獲取函數(shù)地址,也可以獲取變量地址。handle是由dlopen打開動(dòng)態(tài)鏈接庫后返回的指針,symbol就是要求獲取的函數(shù)或全局變量的名稱。
(3)卸載共享庫?dlcloseint dlclose (void *handle)函數(shù)功能:dlclose用于關(guān)閉指定句柄的動(dòng)態(tài)鏈接庫,只有當(dāng)此動(dòng)態(tài)鏈接庫的使用計(jì)數(shù)為0時(shí),才會(huì)真正被系統(tǒng)卸載。
(4)獲取錯(cuò)誤信息?dlerrorconst char *dlerror(void)函數(shù)功能:當(dāng)動(dòng)態(tài)鏈接庫操作函數(shù)執(zhí)行失敗時(shí),dlerror可以返回出錯(cuò)信息,返回值為NULL時(shí)表示操作函數(shù)執(zhí)行成功。
舉個(gè)栗子:生成共享庫文件:gcc -shared add.o -o libadd.so ?將上面?main.c 改為如下,使用動(dòng)態(tài)度顯示調(diào)用函數(shù),調(diào)用 add_int 函數(shù):#include <stdio.h> #include <stdlib.h> #include <dlfcn.h> //動(dòng)態(tài)鏈接庫路徑 #define LIB_ADD_PATH "./libadd.so" //函數(shù)指針 typedef int (*ADD_FUNC) (int, int); int main (void) { void *handle; char *error; ADD_FUNC add_func = NULL; //打開動(dòng)態(tài)鏈接庫 handle = dlopen (LIB_ADD_PATH, RTLD_LAZY); if (!handle) { fprintf (stderr, "%s\n", dlerror ()); exit (EXIT_FAILURE); } //清除之前存在的錯(cuò)誤 dlerror (); //獲取一個(gè)函數(shù) add_func = (ADD_FUNC)dlsym (handle, "add_int"); if (!add_func){fprintf (stderr, "%s\n", dlerror ()); exit (EXIT_FAILURE); }printf ("計(jì)算兩個(gè)整數(shù)的和是:%d\n", add_func (20, 40)); if(dlclose (handle)){fprintf (stderr, "%s\n", dlerror ()); exit (EXIT_FAILURE); }return 0; } 編譯選項(xiàng)如下:gcc -rdynamic -o add main.c -ldl
執(zhí)行 ./add 輸出結(jié)果: 計(jì)算兩個(gè)整數(shù)的和是:60
六、庫相關(guān)命令
(1)nm命令
參看:C語言再學(xué)習(xí)-- readelf、objdump、nm使用詳解 其中,nm 命令可以打印庫中所涉及到的所有符號,既可以用以靜態(tài)庫也可以用以共享庫。 //用于共享庫 # nm libadd.so 00001f28 a _DYNAMIC 00001ff4 a _GLOBAL_OFFSET_TABLE_w _Jv_RegisterClasses 00001f18 d __CTOR_END__ 00001f14 d __CTOR_LIST__ 00001f20 d __DTOR_END__ 00001f1c d __DTOR_LIST__ 000004ec r __FRAME_END__ 00001f24 d __JCR_END__ 00001f24 d __JCR_LIST__ 0000200c A __bss_startw __cxa_finalize@@GLIBC_2.1.3 00000420 t __do_global_ctors_aux 00000350 t __do_global_dtors_aux 00002008 d __dso_handlew __gmon_start__ 00000407 t __i686.get_pc_thunk.bx 0000200c A _edata 00002014 A _end 00000458 T _fini 000002f0 T _init 0000040c T add_int 0000200c b completed.6159 00002010 b dtor_idx.6161 000003d0 t frame_dummy//用于靜態(tài)庫 nm libadd.a add.o: 00000000 T add_intnm列出的符號有很多,常見的有三種:1) 一種是在庫中被調(diào)用,但并沒有在庫中定義(表明需要其他庫支持),用U表示;
2) 一種是庫中定義的函數(shù),用T表示,這是最常見的;
3) 一種是所謂的弱態(tài)”符號,它們雖然在庫中被定義,但是可能被其他庫中的同名符號覆蓋,用W表示。
2、ldd命令
ldd命令,可以查看一個(gè)可執(zhí)行程序依賴的共享庫。 //查看靜態(tài)庫,錯(cuò)誤 #ldd libadd.a 不是動(dòng)態(tài)可執(zhí)行文件//查看共享庫 # ldd libadd.so linux-gate.so.1 => (0xb7772000)libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75b6000)/lib/ld-linux.so.2 (0xb7773000)3、strip 命令
去除目標(biāo)文件、可執(zhí)行文件、靜態(tài)庫和共享庫中的符號表、調(diào)試信息等。# strip add參看:linux下strip的用法strip經(jīng)常用來去除目標(biāo)文件中的一些符號表、調(diào)試符號表信息,以減小程序的大小,在rpmbuild包的最后就用到。
用法:strip <選項(xiàng)> 輸入文件
從文件中刪除符號和節(jié)
?選項(xiàng)為:
-I --input-target=<bfdname> Assume input file is in format <bfdname>-O --output-target=<bfdname> Create an output file in format <bfdname>-F --target=<bfdname> Set both input and output format to <bfdname>-p --preserve-dates Copy modified/access timestamps to the output-R --remove-section=<name> Remove section <name> from the output-s --strip-all Remove all symbol and relocation information-g -S -d --strip-debug Remove all debugging symbols & sections--strip-unneeded Remove all symbols not needed by relocations--only-keep-debug Strip everything but the debug information-N --strip-symbol=<name> Do not copy symbol <name>-K --keep-symbol=<name> Do not strip symbol <name>--keep-file-symbols Do not strip file symbol(s)-w --wildcard Permit wildcard in symbol comparison-x --discard-all Remove all non-global symbols-X --discard-locals Remove any compiler-generated symbols-v --verbose List all object files modified-V --version Display this program's version number-h --help Display this output--info List object formats & architectures supported-o <file> Place stripped output into <file>strip: 支持的目標(biāo): elf32-i386 a.out-i386-linux efi-app-ia32 elf32-little elf32-big elf64-alpha ecoff-littlealpha elf64-little elf64-big elf32-littlearm elf32-bigarm elf32-hppa-linux elf32-hppa elf64-ia64-little elf64-ia64-big efi-app-ia64 elf32-m68k a.out-m68k-linux elf32-powerpc aixcoff-rs6000 elf32-powerpcle ppcboot elf64-powerpc elf64-powerpcle aixcoff64-rs6000 elf32-s390 elf64-s390 elf32-sparc a.out-sparc-linux elf64-sparc a.out-sunos-big elf64-x86-64 pe-i386 pei-i386 srec symbolsrec tekhex binary ihex trad-core目標(biāo)文件分為:可重定位文件、可執(zhí)行文件、共享文件
strip的默認(rèn)選項(xiàng)會(huì)去除.symbol節(jié)的內(nèi)容以及.debug節(jié)的內(nèi)容,因此盡量只對可執(zhí)行文件執(zhí)行strip而不要對靜態(tài)庫或動(dòng)態(tài)庫等目標(biāo)文件strip。
測試:生成目標(biāo)文件 add.o main.o: gcc -c add.c main.c 生成靜態(tài)庫文件 libadd.a: ar -r libadd.a add.o 生成可執(zhí)行文件 add_a: gcc main.o libadd.a -o add_a 生成目標(biāo)文件 add.o main.o: gcc -c -fpic add.c main.c 生成共享庫文件 libadd.so: gcc -shared add.o -o libadd.so 生成可執(zhí)行文件add_so: gcc main.o libadd.so -o add_so 做備份,使用strip指令 strip add_a add_so libadd.a libadd.so main.o add.o # ls -l 總用量 84 -rwxr-xr-x 1 root root 5516 Mar 20 10:38 add_a -rwxr-xr-x 1 root root 7206 Mar 20 10:33 add_a_bak -rw-r--r-- 1 root root 80 Mar 17 14:23 add.c -rw-r--r-- 1 root root 147 Mar 17 14:23 add.h -rw-r--r-- 1 root root 596 Mar 20 10:38 add.o -rw-r--r-- 1 root root 860 Mar 20 10:38 add.o_bak -rwxr-xr-x 1 root root 5520 Mar 20 10:38 add_so -rwxr-xr-x 1 root root 7188 Mar 20 10:34 add_so_bak -rw-r--r-- 1 root root 728 Mar 20 10:38 libadd.a -rw-r--r-- 1 root root 1004 Mar 20 10:34 libadd.a_bak -rwxr-xr-x 1 root root 5356 Mar 20 10:38 libadd.so -rwxr-xr-x 1 root root 6654 Mar 20 10:34 libadd.so_bak -rw-r--r-- 1 root root 123 Mar 20 10:20 main.c -rw-r--r-- 1 root root 876 Mar 20 10:38 main.o -rw-r--r-- 1 root root 1416 Mar 20 10:34 main.o_bak
選項(xiàng)簡釋:
The -fPIC flag directs the compiler to generate position independent code section).
The -shared flag directs the linker to create a shared object file.
可見無論是靜態(tài)庫 (libadd.a) 還是動(dòng)態(tài)庫 (libadd.so) 還是可執(zhí)行文件(add_a、add_so),去掉一些符號信息后都減小了很多,但如果這時(shí)再鏈接這兩個(gè)庫的話是編不過的,因此,如果不是指定特殊的 strip 選項(xiàng)的話,還是盡量不要對庫文件 strip,只對鏈接后的可執(zhí)行文件 strip 就可以了 (如果也不調(diào)試) 。
簡而言之,strip 和 -fpic 正好相反 ,一個(gè)是去除符號信息,一個(gè)為添加符號信息。4、ldconfig 命令
用專門的配置文件管理共享庫的搜索路徑。事先將共享庫的路徑信息寫入 /etc/ld.so.conf 配置文件中。執(zhí)行 ldconfig 命令,將 /etc/ld.so.conf 配置文件轉(zhuǎn)換為 /etc/ld.so.cache 緩沖文件,并將后者加載到系統(tǒng)內(nèi)存中,借以提高共享庫的搜索和加載速度。每次系統(tǒng)啟動(dòng)時(shí)都會(huì)自動(dòng)執(zhí)行 ldconfig 命令。如果修改了共享庫配置文件 /etc/ld.so.conf,則需要手動(dòng)執(zhí)行 ldconfig 命令,更新緩沖文件并重新加載到系統(tǒng)內(nèi)存。5、ls -l 命令
ls -l命令,查看庫大小。 # ls -l libadd.* -rw-r--r-- 1 root root 1004 Mar 17 15:24 libadd.a -rwxr-xr-x 1 root root 6654 Mar 17 15:24 libadd.so 查看屬性,也可以得到:七、Windows下靜態(tài)庫和動(dòng)態(tài)庫操作
參看:程序員的自我修養(yǎng)--鏈接、裝載與庫(高清帶完整書簽版).pdf? 在此不作講解。八、感言
花了兩天半總結(jié)完,靜態(tài)庫和動(dòng)態(tài)庫。一開始真沒覺得能講這么多東西,越發(fā)感到對之前培訓(xùn)時(shí)淺嘗輒止的慚愧。 踏實(shí)一點(diǎn)吧,深入學(xué)習(xí),才是關(guān)鍵!總結(jié)
以上是生活随笔為你收集整理的UNIX再学习 -- 静态库与共享库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UNIX再学习 -- 环境变量
- 下一篇: 互联网晚报 | 04月05日 星期二 |