Linux 中 動(dòng)態(tài)庫和靜態(tài)庫編譯和使用
為了更好的表述,這里寫了一個(gè)簡單的示例代碼 示例代碼 源代碼鏈接
代碼目錄結(jié)構(gòu)為:
.
├── hello # 寫的一個(gè)hello示例庫
│ ├── hello.c
│ ├── include
│ │ └── hello.h
│ └── makefile
├── main.c # 使用main函數(shù)去使用上面的庫
└── makefile
其中 hello.c內(nèi)容:
#include "include/hello.h"
void say_hello(char * name){
printf("Hello, %s!\n", name);
}
其中 hello.h內(nèi)容:
#include<stdio.h>
void say_hello(char *name);
其中 main.h內(nèi)容:
#include<hello.h>
int main(){
say_hello("Tom");
}
靜態(tài)庫編譯
切換目的到hello, 執(zhí)行一下命令可生成靜態(tài)庫
gcc -c -o hello.o hello.c -fpic # 編譯源文件hello.c 到目標(biāo)文件hello.o
ar -rc libhello.a hello.o # ar 打包成一個(gè)靜態(tài)庫
其中g(shù)cc的 -fpic 標(biāo)志含義是:生成使用相對(duì)地址無關(guān)的目標(biāo)代碼
注意: 靜態(tài)庫要以lib開頭,和.a結(jié)束 的方式命名
動(dòng)態(tài)庫的編譯
切換目的到hello, 執(zhí)行一下命令可生成動(dòng)態(tài)庫
gcc -c -o hello.o hello.c -fpic # 編譯源文件hello.c 到目標(biāo)文件hello.o
gcc -shared -fpic -o libhello.so hello.o # 生成動(dòng)態(tài)庫
注意: 動(dòng)態(tài)庫要以lib開頭,和.so結(jié)束 的方式命名
如果你下載我提供的代碼,也可以直接使用make編譯
靜態(tài)庫的使用
切換目錄回到主目錄, 編譯main.c 并使用剛才編譯好的靜態(tài)庫
gcc -c -o main.o main.c -Ihello/include # 這里-Ihello/include 指定頭文件查找目錄為相對(duì)路徑hello/include
# 這一定要指定頭文件查找目錄的,不然找不到main.c中使用的hello.h
gcc -o main_a main.o -Lhello -lhello -static
# 這里 -Lhello 指定庫查找目錄為相對(duì)路徑hello
# -lhello 指定需要鏈接的庫為hello, 優(yōu)先鏈接libhello.so,如何找不到就鏈接libhello.a
# -static 指定要鏈接靜態(tài)庫, 因?yàn)閔ello目錄中同時(shí)存在靜態(tài)庫和動(dòng)態(tài)庫,所以需要特別指定
最后生成 main_a , 可以直接通過 ./main_a 運(yùn)行
動(dòng)態(tài)庫的使用
切換目錄回到主目錄, 編譯main.c 并使用剛才編譯好的動(dòng)態(tài)庫
gcc -c -o main.o main.c -Ihello/include
gcc -o main_so main.o -Lhello -lhello -Wl,-rpath=./hello
相比使用靜態(tài)庫,使用動(dòng)態(tài)庫需要指定的查找目錄 -Wl,-rpath=./hello
這里指定的目錄,是編譯完成的程序運(yùn)行的時(shí)候,去找依賴的動(dòng)態(tài)庫的路徑,如果你沒有指定,程序會(huì)
到系統(tǒng)默認(rèn)的路徑去找,如果沒有找到會(huì)報(bào)錯(cuò)(如下)
./main_so: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
最后生成 main_so , 可以直接通過 ./main_so 運(yùn)行
動(dòng)態(tài)庫和靜態(tài)庫的區(qū)別
- 鏈接時(shí)不同
靜態(tài)庫鏈接的時(shí)候,會(huì)把靜態(tài)庫中自己需要的代碼復(fù)制到自己的程序里面去。
動(dòng)態(tài)庫鏈接的時(shí)候,只會(huì)檢查一下動(dòng)態(tài)庫只是否有自己程序需要的代碼,不會(huì)復(fù)制。 - 運(yùn)行時(shí)不同
靜態(tài)庫因?yàn)殒溄訒r(shí)已經(jīng)把相關(guān)代碼復(fù)制進(jìn)程序了,所以運(yùn)行時(shí)不再依賴靜態(tài)庫。
相反,使用動(dòng)態(tài)的程序在運(yùn)行時(shí)需要去找依賴的動(dòng)態(tài)庫,如果找不到會(huì)導(dǎo)致無法運(yùn)行。
靜態(tài)庫優(yōu)點(diǎn)
- 運(yùn)行效率高些,無需依賴,簡單方便。
動(dòng)態(tài)庫的優(yōu)點(diǎn)
- 節(jié)約內(nèi)存(主要體現(xiàn)在:因?yàn)閯?dòng)態(tài)庫可多個(gè)程序共享一份,當(dāng)多個(gè)程序都在使用這個(gè)動(dòng)態(tài)庫時(shí),內(nèi)存中只加載一份)
-
節(jié)約時(shí)間(如果庫修改代碼,只需要重新編譯動(dòng)態(tài)庫,然后替換掉原先的庫。相反靜態(tài)庫需要編譯所有使用這個(gè)庫的程序)
