庫檔案命名慣例
- 靜態庫:
libxxx.a(archive)
- 動態庫:
libxxx.so(shared object)
- 版本管理:
libxxx.so.1.0 → 建立符號連結 libxxx.so.1 → libxxx.so,連結器尋找 .so 後綴,執行期載入器依 SONAME(如 libxxx.so.1)定位具體版本。
連結機制差異
| 特性 | 靜態庫 | 動態庫 |
| 連結時期 | 將符號完整複製至執行檔 | 在執行檔留下標記,執行時動態載入 |
| 體積 | 執行檔較大 | 執行檔較小,共享庫體 |
| 部署 | 無外部依賴 | 需確保運行環境有對應 .so |
| 預設行為 | 需顯式指定 | GCC 預設優先動態連結 |
實戰:同目錄同時存在靜/動態庫時的連結控制
# 預設動態連結
gcc testlib.o -lhello -o testlib
# 強制靜態連結 hello,動態連結 bye
gcc testlib.o -o testlib -Wl,-Bstatic -lhello -Wl,-Bdynamic -lbye
-Wl,-Bstatic 傳遞給連結器 ld,後續 -l 走靜態;-Wl,-Bdynamic 恢復動態。
- 若系統僅有靜態庫,無需額外參數。
動態庫路徑搜尋順序與配置
- 編譯時期
-L 指定目錄(僅影響連結器)。
- 執行期依序搜尋:
- 編譯時嵌入的
RPATH/RUNPATH
- 環境變數
LD_LIBRARY_PATH
/etc/ld.so.conf 內目錄(需執行 ldconfig 刷新快取)
- 預設
/lib、/usr/lib
# 臨時指定
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ting/lib
# 永久生效
echo "/home/ting/lib" >> /etc/ld.so.conf
ldconfig
查看庫符號:nm & ldd
# nm 輸出符號類型:T=定義在本庫、U=未定義(需外部)、W=弱符號
nm libhello.so | grep printf
# 輸出: U printf → printf 來自外部庫
# ldd 查看動態依賴
ldd libhello.so
# libc.so.6 => /lib/libc.so.6
# /lib/ld-linux.so.2 => /lib/ld-linux.so.2
從原始碼製作庫完整流程
# hello.c
#include
void sayhello() { printf("hello,world"); }
1. 編譯目標檔
gcc -c hello.c -o hello.o # 可加 -g 保留除錯資訊
2. 產生靜態庫
ar cqs libhello.a hello.o
3. 產生動態庫
gcc -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 hello.o
ln -sf libhello.so.1.0 libhello.so.1
ln -sf libhello.so.1 libhello.so
-shared 生成共享庫而非執行檔。
-Wl,-soname,libhello.so.1 設定 SONAME 嵌入執行檔,實現版本相容。
- 慣例命名:
libxxx.so.主版本.次版本,SONAME 只保留主版本。