Summary
1)連結的定義:將目標檔案最終連結為可執行程式
2)連結的2種方式:
- 靜態連結:
目標檔案會被直接*連結*進可執行程式
。slib.a
被刪掉後,程式依舊可以執行 - 動態連結:
程式啟動後才動態載入目標檔案
。dlib.so
被刪掉後,程式無法執行
3)靜態連結和動態連結方式的抉擇:
- 靜態連結:適用於比較簡單的程式,開發出來不需要變動的,比如純本地的記事本這種;把
所有目標檔案都編到可執行程式裡,可能會導致可執行程式很大
。 - 動態連結:一個大型軟體的各個模組,如果採用動態庫的形式,
哪個模組需要更新了,只需要修改這個模組,然後把dlib.so傳到伺服器上
。使用者在使用軟體時,直接去伺服器上拿這一個庫更新下就可以了,而不需要更新整個程式。
連結過程簡介
問題:工程裡的每個.c原始檔
在編譯後都會生成目標檔案.o
,那這些.o檔案怎麼生成最終的可執行程式.out
呢?
答:連結器
的主要作用是把各個模組間相互引用的部分處理好
,使得各個模組之間能正常的銜接。
1、靜態連結
- 連結器在
連結時將庫的內容直接加入到可執行程式中
- 靜態庫的建立和使用
1)生成靜態庫目標檔案
:gcc -c slib.c -o slib.o
2)生成靜態庫
:ar -q slib.a slib.o (輸出:ar:creating slib.a;ar指的是archive,把後面列出的所有目標檔案全都打包進slib.a中
)
3)使用靜態庫編譯
:gcc 20-1.c slib.a -o 20-1.out (使用靜態庫進行編譯)
2、動態連結
- 可執行程式在
執行時才動態載入庫進行連結
(執行時才去找我需要的symbol) 庫的內容不會進入到可執行程式中
// dlib.c
char* name()
{
return "Dynamic Lib";
}
int add(int a, int b)
{
return a+b;
}
// 20-2.c
#include <stdio.h>
#include <dlfcn.h>
int main()
{
void* pdlib = dlopen("./dlib.so", RTLD_LAZY); // pdlib指向了目錄下dlib.so這個動態庫
// 這個開啟就相當於一個載入到記憶體裡的指標
char* (*pName)(); // 定義函式指標
int (*pAdd)(int, int);
if(NULL != pdlib)
{
pName = dlsym(pdlib, "name"); // 查詢pdlib指向的動態庫裡的函式
pAdd = dlsym(pdlib, "add");
if(NULL != pName && NULL != pAdd)
{
printf("Name: %s\n", pName());
printf("Ret: %d\n", pAdd(2, 3));
}
dlclose(pdlib); // 關閉pdlib指向的動態庫
}
else
{
printf("Cannot open dynamic lib...");
}
}
// linux命令
gcc -shared dlib.c -o dlib.so : 建立了動態庫dlib.so
gcc 20-2.c -ldl -o a.out : 使用動態庫建立了可執行程式a.out
./a.out : 執行可執行程式
注意:-ldl告訴編譯器,這個程式用動態庫的方式來編譯
,我們的程式依賴動態庫。如果動態庫dlib.so刪掉了,這個程式就執行不起來了
,輸出cannot open,因為a.out每次執行時需要去動態庫裡找symbol的(我要用啥,我每次得去你的倉庫裡拿),庫都沒了,自然找不到了。
本文總結自“狄泰軟體學院”唐佐林老師《C語言進階課程》。
如有錯漏之處,懇請指正。