靜態函式庫 (.a, Archive) 將多個目標檔 (.o) 打包成單一檔案,連結時將所需機器碼直接複製至執行檔,無執行期相依性、啟動快、部署簡單。本文以雙函式示範完整流程:原始碼編譯 → ar 打包 → 主程式連結 → 執行驗證,並說明兩種連結方式差異。
static_lib_demo/
├── hello_first.c
├── hello_second.c
├── hello_main.c
└── Makefile (選用)
#include <stdio.h>
void hello_first(void) {
printf("hello first\n");
}
#include <stdio.h>
void hello_second(void) {
printf("hello second\n");
}
#include <stdio.h>
void hello_first(void);
void hello_second(void);
int main(void) {
hello_first();
hello_second();
return 0;
}
gcc -c hello_first.c -o hello_first.o
gcc -c hello_second.c -o hello_second.o
# 驗證
file hello_first.o
# hello_first.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
-c:僅編譯組譯,不連結,產生 .o 目標檔。
ar -rcs libhello.a hello_first.o hello_second.o
參數說明:
r:插入/替換模組c:建立新檔案不提示s:建立/更新符號索引 (ranlib 功能),連結器需要此索引驗證庫內容:
ar -t libhello.a
# hello_first.o
# hello_second.o
nm -s libhello.a
# 顯示符號表與索引
gcc hello_main.c libhello.a -o hello_main
./hello_main
# 輸出:
# hello first
# hello second
# 1. 複製庫至標準路徑 (需 root)
sudo cp libhello.a /usr/local/lib/
sudo ldconfig
# 2. 連結時使用 -lhello (去掉 lib 前綴與 .a 後綴)
gcc hello_main.c -lhello -o hello_main2
./hello_main2
# 輸出相同
gcc hello_main.c -L. -lhello -o hello_main3
# -L. 表示當前目錄為搜尋路徑
| 特性 | 靜態庫 (.a) | 動態庫 (.so) |
|---|---|---|
| 副檔名 | .a (Linux/Unix), .lib (Windows) | .so (Linux), .dll (Windows), .dylib (macOS) |
| 連結時機 | 編譯時 (靜態連結) | 執行時 (動態連結) |
| 執行檔大小 | 較大 (含庫程式碼) | 較小 (僅含符號參考) |
| 記憶體佔用 | 每進程獨立載入副本 | 進程間共享單一副本 |
| 部署相依性 | 無 (獨立執行檔) | 需目標系統有對應 .so |
| 更新機制 | 需重新編譯連結 | 替換 .so 檔即可 (注意 ABI 相容) |
| 符號可見性 | 全部內含 | 可控制導出符號 |
# Makefile
CC = gcc
AR = ar
CFLAGS = -Wall -O2
TARGET = hello_main
LIB = libhello.a
OBJS = hello_first.o hello_second.o
all: $(TARGET)
$(LIB): $(OBJS)
$(AR) -rcs $@ $^
$(TARGET): hello_main.c $(LIB)
$(CC) $(CFLAGS) -o $@ hello_main.c $(LIB)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o $(LIB) $(TARGET)
.PHONY: all clean
make
make clean
| 錯誤 | 原因與解決 |
|---|---|
undefined reference to 'hello_first' | 庫未正確連結:檢查 -lhello 拼寫、-L 路徑、庫確實包含該符號 (nm libhello.a | grep hello_first) |
ar: libhello.a: File format not recognized | 檔案損毀或非 ELF 格式,重新 ar -rcs |
| 執行檔極大 | 靜態連結預期行為,若需縮小請改用動態庫或 strip 移除符號表 |
| 多執行緒程式靜態連結 pthread | 需 -pthread 編譯與連結旗標,非單純 -lpthread |
.h + .a,隱藏實作細節,使用者只需知道函式簽名。Linux 建立靜態函式庫核心三步驟:gcc -c 編譯 .o → ar -rcs 打包 .a → gcc -L. -lhello 連結驗證。掌握 ar 參數 (rcs)、連結搜尋順序 (-L、-l)、符號索引 (nm -s) 即可獨立完成靜態庫開發與部署。