本文討論了linux動態庫 靜態庫中函式的覆蓋問題。
測試目的:
同名函式,分別打成動態庫libdync_lib.so與靜態庫libstatic_lib.a,並把libstatic_lib.a打到另一個動態庫libapi.so中,
在可執行程式中分別連線libdync_lib.so與libapi.so,此時到底呼叫的是哪個庫中的函式?
測試結論:
不同庫中的同名函式會被覆蓋,後連結的庫中的同名函式會被先前庫覆蓋。
測試方法:
static_lib.h
1 void print();
static_lib.cpp
1 #include <cstdio.h> 2 #include "static_lib.h" 3 4 void print() 5 { 6 printf("i am static print\n"); 7 }
dync_lib.h
1 void print();
dync_lib.cpp
#include <cstdio.h> #include "dync_lib.h" void print() { printf("i am dync print\n"); }
api.h
void func();
api.cpp
1 #include "static_lib.h" 2 3 void func() 4 { 5 print(); 6 }
main.cpp
#include <api.h> int main() { func(); print(); return 0; }
製作libdync_lib.so動態庫
g++ dync_lib.cpp -shared -fPIC -o libdync_lib.so
製作libstatic_lib.a靜態庫
g++ -c static_lib.cpp -share -fPIC -o static_lib.o
ar crv libstatic_lib.a static_lib.o
製作libapi.so動態庫,其依賴靜態庫libstatic_lib.a
g++ api.cpp -shared -fPIC -o libapi.so -lstatic_lib
有三種方式生成可執行程式
1、g++ main.cpp -lapi -o main
2、g++ main.cpp -lapi -ldync_lib -o main
3、g++ main.cpp -ldync_lib -lapi -o main
每種方式都能執行成功,但輸出不一樣,
1、2執行時,輸出一致:
i am static print
3執行時,輸出;
i am dync print
下面分析原因:
1、第一種方式中,main.cpp中只包含了 api.h,而api.h中並沒有定義print函式,那麼main中怎麼找到了該函式並且呼叫成功了呢?
因為,生成libapi.so時連線了libstatic_lib.a,而其中包含print,也就是說,靜態庫中的函式符號都會被打到動態庫中,所以main能找到print函式的實現,來自libstatic_lib.a。
2、後2種方式中,只是額外連結libdync_lib.so,但連結的順序不同。從結果中看,程式正常執行。
第二種方式呼叫的是libstatic_lib.a中的print函式,對比發現,第三種呼叫的是libdync_lib.so中的print。
也就是說,根據連結的順序,先被連結的庫中的符號(函式)會覆蓋後面庫中的同名符號。