Bài 39.924 phút đọc
Đánh số phiên bản và SONAME
Sau bài này bạn sẽ làm được
- Đặt SONAME khi tạo thư viện chia sẻ
- Giải thích ba tầng liên kết tượng trưng và vai trò từng cái
- Áp dụng quy tắc MAJOR MINOR PATCH cho thay đổi ABI
- Biết khi nào bắt buộc phải tăng số MAJOR
Ba tệp cho một thư viện nghe có vẻ rườm rà, nhưng mỗi cái giải quyết một vấn đề khác nhau: một cái cho người dịch, một cái cho chương trình đang chạy, một cái là tệp thật.
#Ba tệp, ba vai trò
gcc -shared -Wl,-soname,libmath.so.1 *.o -o libmath.so.1.2.3
ln -sf libmath.so.1.2.3 libmath.so.1 # SONAME
ln -sf libmath.so.1 libmath.so # ten khi lien ket
$ ls -l
lrwxrwxrwx libmath.so -> libmath.so.1
lrwxrwxrwx libmath.so.1 -> libmath.so.1.2.3
-rwxr-xr-x libmath.so.1.2.3| Tên | Ai dùng | Khi nào |
|---|---|---|
| libmath.so | Trình liên kết | Lúc dịch, khi bạn viết -lmath |
| libmath.so.1 | Trình nạp động | Lúc chạy, tên này được ghi vào tệp nhị phân |
| libmath.so.1.2.3 | Người quản trị và trình quản lý gói | Tệp thật trên đĩa, để biết chính xác bản nào đang cài |
#SONAME làm gì
SONAME
Một chuỗi ghi bên trong tệp thư viện. Khi trình liên kết dùng thư viện đó, nó chép chuỗi này vào tệp nhị phân thay vì chép tên tệp. Lúc chạy, trình nạp tìm đúng chuỗi đó.
$ objdump -p libmath.so.1.2.3 | grep SONAME
SONAME libmath.so.1
$ gcc app.c -L. -lmath -o app # -lmath tim thay libmath.so
$ objdump -p app | grep NEEDED
NEEDED libmath.so.1 # KHONG phai libmath.so
/* Trinh lien ket doc SONAME tu thu vien va ghi CHUOI DO vao app.
Nen luc chay, app tim libmath.so.1, khong phai libmath.so.
Do la ly do ban co the xoa lien ket tuong trung libmath.so
sau khi dich xong ma chuong trinh van chay. Cac ban phan phoi
Linux dua vao dieu nay: goi "libmath1" chua tep .so.1, con goi
"libmath-dev" moi chua lien ket .so va cac header. */Makefile với đầy đủ ba mức
TEN = math
CHINH = 1
PHU = 2
VA = 3
SO_DAY = lib$(TEN).so.$(CHINH).$(PHU).$(VA)
SO_NAME = lib$(TEN).so.$(CHINH)
SO_LINK = lib$(TEN).so
$(SO_DAY): $(DOI_TUONG)
$(CC) -shared -Wl,-soname,$(SO_NAME) $^ -o $@
ln -sf $(SO_DAY) $(SO_NAME)
ln -sf $(SO_NAME) $(SO_LINK)
cai: $(SO_DAY)
install -D -m 755 $(SO_DAY) $(DESTDIR)/usr/local/lib/$(SO_DAY)
ln -sf $(SO_DAY) $(DESTDIR)/usr/local/lib/$(SO_NAME)
ln -sf $(SO_NAME) $(DESTDIR)/usr/local/lib/$(SO_LINK)
install -D -m 644 include/$(TEN).h $(DESTDIR)/usr/local/include/$(TEN).h
ldconfig
.PHONY: cai#Semantic versioning cho thư viện
| Loại thay đổi | Số nào tăng | SONAME đổi | Ví dụ |
|---|---|---|---|
| Sửa lỗi, không đổi API hay ABI | PATCH | Không | 1.2.3 thành 1.2.4 |
| Thêm hàm mới, ABI cũ còn nguyên | MINOR | Không | 1.2.3 thành 1.3.0 |
| Phá vỡ ABI | MAJOR | CÓ | 1.2.3 thành 2.0.0, SONAME thành libmath.so.2 |
Phá ABI mà giữ SONAME
# Ban 1.5.0 -> 1.6.0
# Thay doi: doi kieu tra ve cua ml_luu tu int sang long
gcc -shared -Wl,-soname,libmath.so.1 *.o -o libmath.so.1.6.0
/* SONAME van la .so.1, nen moi chuong trinh cu tu dong dung
ban moi va nhan sai kieu tra ve.
Loi im lang tren toan he thong. Day la kich ban te nhat
trong ca phan nay. */Phá ABI thì đổi SONAME
# Ban 1.5.0 -> 2.0.0
gcc -shared -Wl,-soname,libmath.so.2 *.o -o libmath.so.2.0.0
# Va GIU LAI ban 1 tren he thong:
/usr/lib/libmath.so.1 -> libmath.so.1.5.0
/usr/lib/libmath.so.2 -> libmath.so.2.0.0
/* Chuong trinh cu tim .so.1, tim thay, chay dung.
Chuong trinh moi tim .so.2, chay dung.
Ca hai song song, khong ai anh huong ai. */#Trên Windows
terminal
objdump -p app_dyn.exe | grep 'DLL Name'
DLL Name: libmath.dll DLL Name: KERNEL32.dll DLL Name: msvcrt.dll
# Cach dat ten co so phien ban tren MinGW:
gcc -shared *.o -o libmath1.dll -Wl,--out-implib,libmath.dll.a
# DLL co so 1 trong ten
# Thu vien nhap KHONG co so, nen nguoi dung van viet -lmath
#
# Khi len ban 2, ban tao libmath2.dll va mot thu vien nhap moi.
# Chuong trinh cu van tim libmath1.dll, ban ay van con tren dia.
# Va thu tu tim DLL cua Windows:
# 1. Thu muc chua tep exe <- quan trong nhat
# 2. Thu muc he thong (System32)
# 3. Thu muc Windows
# 4. Thu muc hien tai
# 5. Cac thu muc trong PATH
#
# Tu Windows 7 co che do an toan bo buoc 4 di, vi no la lo hong
# bao mat: ke tan cong dat mot DLL gia trong thu muc hien tai.#Kiểm tra phiên bản lúc chạy
Ba thứ cần có trong header
/* mathlib.h */
#define ML_PHIEN_BAN_CHINH 1
#define ML_PHIEN_BAN_PHU 2
#define ML_PHIEN_BAN_VA 3
#define ML_PHIEN_BAN \
(ML_PHIEN_BAN_CHINH * 10000 + ML_PHIEN_BAN_PHU * 100 + ML_PHIEN_BAN_VA)
#define ML_PHIEN_BAN_CHUOI "1.2.3"
/* Va MOT HAM, vi macro o tren la phien ban LUC DICH: */
unsigned ml_phien_ban(void); /* phien ban LUC CHAY */
const char *ml_phien_ban_chuoi(void);Người dùng kiểm tra
#include <stdio.h>
#include "mathlib.h"
int main(void) {
unsigned luc_dich = ML_PHIEN_BAN;
unsigned luc_chay = ml_phien_ban();
printf("dich voi %s, chay voi %s\n",
ML_PHIEN_BAN_CHUOI, ml_phien_ban_chuoi());
if (luc_chay / 10000 != luc_dich / 10000) {
fprintf(stderr, "sai ban CHINH: can %u, co %u\n",
luc_dich / 10000, luc_chay / 10000);
return 1;
}
if (luc_chay < luc_dich) {
fprintf(stderr, "thu vien qua cu\n");
return 1;
}
...
}Tự làm thử
- Tạo thư viện với
-Wl,-sonamevà ba liên kết tượng trưng. - Xác nhận bằng
objdump -prằng chương trình phụ thuộc SONAME chứ không phải tên tệp. - Quên
-soname, dịch chương trình, rồi xem nó phụ thuộc vào gì. - Cài hai bản MAJOR khác nhau và chứng minh hai chương trình dùng đúng bản của mình.
- Viết cặp macro và hàm phiên bản, rồi cố tình cho chúng lệch nhau.
- Trên Windows, đặt số phiên bản vào tên DLL và kiểm tra bằng
objdump -p.
Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.
Tóm tắt
- Ba tệp:
.socho trình liên kết,.so.1cho trình nạp,.so.1.2.3là tệp thật. - SONAME là chuỗi ghi trong thư viện; trình liên kết chép nó vào tệp nhị phân thay vì chép tên tệp.
- Quên
-Wl,-sonamelàm chương trình phụ thuộc vào liên kết tượng trưng, tức luôn dùng bản mới nhất. - Đổi SONAME khi và chỉ khi phá vỡ ABI; thêm hàm là MINOR, xóa hàm là MAJOR.
- Windows không có SONAME, nên phải đặt số phiên bản vào tên tệp hoặc để DLL cạnh tệp thực thi.