編譯程式時指定 -L./lib -lglib-2.0 鏈接自帶的 glib-2.28.8,運行時設定 LD_LIBRARY_PATH=./,但 ldd 顯示仍加載系統的 /lib64/libglib-2.0.so.0(2.22.5 版)。
關鍵認知:動態鏈接階段,鏈接器僅驗證符號存在性,將符號標記為「動態鏈接」,並將庫的 SONAME(如 libglib-2.0.so.0)寫入可執行文件的 .dynamic 區。運行時動態鏈接器 ld-linux.so 按搜索順序查找匹配 SONAME 的庫文件,與編譯時使用的具體文件名無關。
即使將庫文件重命名為 libmyglib.so 並用 -lmyglib 鏈接,生成的可執行文件內部仍記錄原 SONAME libglib-2.0.so.0,運行時依然尋找系統庫。
DT_RPATH(已棄用)LD_LIBRARY_PATHDT_RUNPATH/etc/ld.so.cache 緩存/lib、/usr/libLD_LIBRARY_PATH 優先級雖高,但若系統庫在 ld.so.cache 中且同名,某些情況下仍可能優先被找到(視具體 ld-linux.so 實現)。
export LD_PRELOAD=./libglib-2.0.so.0:./libgmodule-2.0.so.0
./test
LD_PRELOAD 指定的庫最優先加載,符號解析時優先使用,完美覆蓋系統庫。ldd 輸出將顯示本地庫路徑。
cp libglib-2.0.so.0.2800.8 /lib64/,極易遺留垃圾、引發版本衝突。sudo ldconfig /opt/glib-2.28.8/lib,將路徑加入系統緩存,影響全局。gcc -Wl,-rpath='$ORIGIN/../lib' -L./lib -lglib-2.0 -o test test.c
$ORIGIN 表示可執行文件所在目錄,部署時將 lib/ 與可執行文件同級放置,無需環境變量,遷移性最佳。
LD_DEBUG=libs ./test # 顯示庫搜索過程
LD_DEBUG=symbols ./test # 顯示符號解析過程
LD_DEBUG=help ./test # 查看所有調試選項
nm -Du /lib64/libglib-2.0.so.0 # 列出動態符號表(未定義+導出)
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| LD_PRELOAD | 無需重編譯、不影響系統、臨時測試理想 | 需每次啟動設置、不適合產品發布 | 開發調試、臨時驗證新版庫 |
| RPATH/RUNPATH | 部署自包含、遷移性強、無環境依賴 | 需重新編譯鏈接 | 產品發布、標準部署流程 |
| 系統級替換 | 全局生效 | 風險極高、破壞其他程式、維護困難 | 極少數情況(如系統級補丁) |