動態函式庫 (Shared Library, .so) 讓多程式共享程式碼、節省記憶體、支援獨立升級。本文以最簡範例完整示範:編譯 .so、鏈接可執行檔、執行期載入路徑解析、版本管理。
/home/test/program/
├── myLibSrc.c # 庫原始碼
├── myLibInclude.h # 對外介面
└── main.c # 測試程式
// myLibInclude.h
#ifndef MYLIB_H
#define MYLIB_H
int myLibSrcFun(void);
#endif
// myLibSrc.c
#include
#include "myLibInclude.h"
int myLibSrcFun(void) {
printf("There is myLibSrcFun()\n");
return 0;
}
// main.c
#include
#include "myLibInclude.h"
int main(int argc, char **argv) {
printf("Main function!\n");
myLibSrcFun();
return 0;
}
# 基礎編譯
gcc -fPIC -shared -o libmyLib.so myLibSrc.c
# 完整編譯 (含除錯資訊、宏定義)
gcc -fPIC -shared -g -DDEBUG -o libmyLib.so myLibSrc.c
-fPIC (Position Independent Code):產生位置無關程式碼,**動態庫必加**,否則載入時需文字重定位 (性能損耗、安全風險)-shared:產生共享物件而非可執行檔lib.so (連結器 -l 自動尋找)# 方法 1:指定庫完整路徑
gcc -o app main.c /home/test/program/libmyLib.so
# 方法 2:-L 指定搜尋目錄 -l 指定庫名 (去 lib 前綴、.so 後綴)
gcc -o app main.c -L/home/test/program -lmyLib
RPATH (編譯時 -Wl,-rpath,/path)LD_LIBRARY_PATHRUNPATH (較 RPATH 低優先級,可被 LD_LIBRARY_PATH 覆蓋)/etc/ld.so.cache 快取 (ldconfig 更新)/lib, /usr/lib (64位: /lib64, /usr/lib64)# 1. 檢查動態相依
ldd ./app
# 輸出:
# linux-vdso.so.1 => ...
# libmyLib.so => /home/test/program/libmyLib.so (0x...)
# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x...)
# /lib64/ld-linux-x86-64.so.2
# 2. 直接執行 (若庫在非標準路徑會失敗)
./app
# 錯誤:error while loading shared libraries: libmyLib.so: cannot open shared object file
# 3. 臨時指定路徑執行
LD_LIBRARY_PATH=/home/test/program ./app
# 輸出:
# Main function!
# There is myLibSrcFun()
# 4. 永久解決:安裝至系統目錄並更新快取
cp libmyLib.so /usr/local/lib/
ldconfig
# 5. 再次執行
./app # 成功
# 編譯時指定 soname (SO-NAME)
gcc -fPIC -shared -Wl,-soname,libmyLib.so.1 -o libmyLib.so.1.0.0 myLibSrc.c
# 建立符號連結
ln -sf libmyLib.so.1.0.0 libmyLib.so.1
ln -sf libmyLib.so.1 libmyLib.so
# 檢查
readelf -d libmyLib.so.1.0.0 | grep SONAME
# 0x000000000000000e (SONAME) Library soname: [libmyLib.so.1]
soname (如 libmyLib.so.1):執行期載入器真正尋找的名稱ldconfig 掃描目錄建立 soname → 實際檔案 符號連結#include
void *handle = dlopen("./libmyLib.so", RTLD_LAZY);
if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(1); }
int (*func)(void) = dlsym(handle, "myLibSrcFun");
if (func) func();
dlclose(handle);
編譯:gcc -o plugin_app main_dl.c -ldl (主程式不連結 .so,執行期載入)
| 錯誤 | 原因 | 解決 |
|---|---|---|
cannot open shared object file | 庫路徑不在搜尋順序中 | LD_LIBRARY_PATH、ldconfig、-Wl,-rpath |
undefined symbol | 符號未導出或版本不符 | nm -D libxxx.so | grep sym、檢查版本 |
wrong ELF class | 32/64 位元不匹配 | file libxxx.so 確認架構 |
| 文字重定位警告 | 未加 -fPIC | 重編譯加 -fPIC |
動態庫是 Linux 模組化、記憶體共享、熱升級的基石。掌握 -fPIC、soname、ldconfig、RPATH/RUNPATH、dlopen 五大核心機制,即可自如構建、部署、維護共享庫生態。