動態庫或者稱為共享庫,是共享**的另外一種實現方式。
其特徵是在程式實際執行時,動態地載入所呼叫的函式或變數等符號,這樣可以減小應用程式檔案的尺寸;而且遇到功能公升級或者修復bug時只要更新庫檔案就可以了,不必更新應用程式。
在windows環境中,對應的動態庫常以*.dll檔案形式存在,意為dynamic link library。
在linux環境下,生成動態庫也很簡單:新增編譯選項,直接將*.c編譯成*.so
例如:
gcc -shared s1.c -o so1.so
而使用動態庫檔案時,呼叫函式使用dlopen,dlsym等函式動態載入so檔案,就能獲取其中的符號了。
例一:
我們現在csdn.c檔案中定義乙個函式fry_it和乙個變數data1
int fry_it(int
*n) return0;}
int data1 = 3;
然後我們就可以把這個原始檔製作成so,命令如下:
test@test
:~$ gcc -shared csdn.c -o libcsdn.so
然後我們再來寫乙個應用程式源**main.c,通過訪問這個so來使用其中的函式和變數
#include
#include
#include
int main()
pf = dlsym(pso, "fry_it");
if(pf)
else
pdata = (int
*) dlsym(pso, "data1");
if(!pdata)
printf("data=%d\n", *pdata);
(*pf)(pdata);
printf("after fried data=%d\n", *pdata);
out:
if(dlclose(pso))
printf("%s return\n", __func__);
return
0;}
必要的,我們需要定義乙個void*型別的指標pso,用來儲存指向開啟的so庫的入口。
在這裡例子中,還定義了函式指標pf和指向變數的指標pdata用來訪問so中的符號。
在成功開啟我們需要的so後,就可以通過pso來搜尋庫中我們需要的符號。符號的意思就是說函式名或者變數名。
把應用程式編譯出來:
test@test
:~$gcc main.c -ldl
test@test
:~$ ./a.out
main begin
fry_it() symbol found
data=3
after fried data=6
main return
例二:
通過例一我們看到了so的製作,使用等基本用法。但是這樣使用so有很致命的缺點:
需要在應用程式中提前預製好藥使用的符號。
例一中只用了簡單的fry_it這乙個函式和data1這乙個變數,萬一將來我們需要增加幾百個函式,或者需要更新fry_it的引數型別怎麼辦?
萬一將來需要增加data2,data3……data100,那麼在應用程式中寫100個dlsym(pso, 「data……嗎?
即使允許可以修改主程式,那麼每改乙個細節都要重新發布一次主程式嗎?如果可以那麼公升級程式前還要解除安裝舊程式嗎?
我們來看例二:
先將so原始檔優化一下
test@test:~$ cat csdn0.c
#include
#include "csdn.h"
int double_it(int
*n) return0;}
csdn_t csdn = ;
把csdn_t的定義放在另外乙個檔案裡,便於引用:
test@test:~$ cat *.h
typedef
struct csdn_t
csdn_t;
製作so:
test@test
:~$ gcc csdn0.c -shared -o libcsdn0.so
然後我們來看怎麼使用:
test@test:~$ cat main0.c
#include
#include
#include
#include "csdn.h"
int main()
pc = (csdn_t *)dlsym(pso, "csdn");
if(pc)
else
printf("data=%d\n", pc->data);
pc->fry_it( &pc->data);
printf("after fried data=%d\n", pc->data);
out:
if(dlclose(pso))
printf("%s return\n", __func__);
return
0;}
編譯時記得引用dl這個lib:
test@test
:~$ gcc main0.c -ldl
例三:
類似的我們來看android原始碼中hal是怎麼使用so的:
在android原始碼中,系統程序統通過函式hw_get_module來載入需要的so檔案,其中的load函式如下:
58
/**59 * load the file defined by the variant and if successful
60 * return the dlopen handle and the hmi.
61 * @return 0 = success, !0 = failure.
62 */
63static
int load(const
char *id,
64const
char *path,
65const
struct hw_module_t **phmi)
66 83
84/* get the address of the struct hal_module_info. */
85const
char *sym = hal_module_info_sym_as_str;
86 hmi = (struct hw_module_t *)dlsym(handle, sym);
87if (hmi == null)
9293
/* check that the id matches */
94if (strcmp(id, hmi->id) != 0)
99100 hmi->dso = handle;
101102
/* success */
103 status = 0;
104105 done:
106if (status != 0)
112 } else
116117 *phmi = hmi;
118119
return status;
120 }
**中hal_module_info_sym_as_str就永遠是hmi這個字串,每個被呼叫的模組在hmi這個結構體中定義自己的各種功能。 共享庫 動態庫
動態庫的命名規則 lib 庫的名字 so libmyname.so 動態庫的建立和使用 共享庫 步驟一 生成對應的.o檔案 c o gcc fpic c c i include 生成與位置無關的.o檔案 fpic 與位置無關 步驟二 將生成的.o檔案打包成動態庫.so檔案 gcc shared o ...
靜態庫,共享庫,動態載入庫
一 靜態庫 1.概念 靜態庫就是一些目標檔案的集合,以.a結尾。靜態庫在程式鏈結的時候使用,鏈結器會將程式中使用 到函式的 從庫檔案中拷貝到應用程式中。一旦鏈結完成,在執行程式的時候就不需要靜態庫了。由於每個使用靜態庫的應用程式都需要拷貝所用函式的 所以靜態鏈結的檔案會比較大。2.建立與應用 首先建...
動態鏈結共享庫
靜態庫有一些明顯的缺陷,它與所有的軟體一樣,需要定期維護和更新。如果應用程式設計師想要使用乙個庫的最新版本,他們必須以某種方式了解到該庫的更新情況,然後顯示的將他們的程式與更新了的庫重新鏈結。其次,幾乎每乙個c程式都使用了標準i o函式,執行時這些函式的 會被複製到每個執行程序的文字段中,在執行上百...