在大型專案開發中,將數百 MB 甚至數 GB 的程式碼全部置於單一執行檔中,不僅編譯耗時,後續維護修改極為繁瑣。透過將不同功能模組封裝為共享函式庫,可實現程式碼複用、減少磁碟佔用、支援獨立更新部署,大幅提升開發效率。本文詳解 Linux 下 C 函式庫的建立、編譯參數、路徑解析與跨語言呼叫實戰。
library/
├── file1/
│ ├── file1.c
│ ├── hello.h
│ └── hello.c
├── file2/
│ ├── file2.c
│ ├── hi.c
│ └── hi.h
├── file3/
│ ├── file3.h
│ └── file3.cpp
└── LIB/ # 存放編譯產出的 .so 檔案
直接編譯共享庫常報錯:relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC。解決方案:加入 -fPIC 參數。
gcc -fPIC --shared play1.c -o libplay1.so
編譯成功但執行報錯 error while loading shared libraries: libplay1.so: cannot open shared object file,因載入器找不到庫檔案。解決方法:
gcc -o file1 file1.c ./libplay1.soLD_LIBRARY_PATH/usr/lib 並執行 ldconfig// file1.h
void play1(void);
// play1.c
#include
void play1(void) { printf("hello file1\n"); }
// file1.c (主程式)
#include
#include "file1.h"
int main(void) { play1(); return 0; }
// hi.h
void hi(void);
// hi.c
#include
void hi(void) { printf("hi file2\n"); }
// file2.c (主程式)
#include
#include "hi.h"
int main(void) { hi(); return 0; }
// file3.h
#ifdef __cplusplus
extern "C" {
#endif
void hi(void);
void play1(void);
#ifdef __cplusplus
}
#endif
// file3.cpp
#include
extern "C" { void play1(void); void hi(void); }
int main(void) { play1(); hi(); return 0; }
# 1. 建立動態庫
gcc -fPIC --shared play1.c -o libplay1.so
gcc -fPIC --shared hi.c -o libfile2.so
# 2. 複製至統一目錄
cp libplay1.so ../LIB/
cp libfile2.so ../LIB/
# 3. C++ 程式連結 C 庫
g++ -o file3 file3.cpp ../LIB/libplay1.so ../LIB/libfile2.so
./file3
# 輸出:
# hello file1
# hi file2
extern "C" 包裹宣告,防止名稱修飾extern "C" 包裹的介面函式gcc,C++ 代碼用 g++,連結時統一用 g++| 錯誤現象 | 原因 | 解決方案 |
|---|---|---|
| relocation R_X86_64_32 | 缺少 -fPIC 參數 | 加入 -fPIC 重新編譯 |
| cannot open shared object file | 執行期找不到 .so | 指定相對路徑 ./libxxx.so 或設定 LD_LIBRARY_PATH |
| undefined reference | 連結順序錯誤或缺少 extern "C" | 調整庫連結順序、檢查 C/C++ 混合宣告 |