Bài 39.126 phút đọc
Thư viện tĩnh chỉ là một kho lưu trữ
Sau bài này bạn sẽ làm được
- Đóng gói nhiều tệp .o thành một tệp .a bằng ar
- Liệt kê và giải nén nội dung một thư viện tĩnh
- Đọc bảng ký hiệu bằng nm và phân biệt T với t
- Giải thích vì sao .a không phải là mã đã liên kết
Một tệp .a không phải mã đã liên kết, không phải mã đã tối ưu, không phải thứ gì đặc biệt cả. Nó là một cái túi đựng các tệp .o, đúng nghĩa như một tệp .tar, cộng thêm một mục lục ký hiệu.
#Nó thật sự là gì
Thư viện tĩnh (static library)
Một kho lưu trữ chứa nhiều tệp đối tượng. Khi liên kết, trình liên kết lấy ra những tệp .o mà chương trình cần rồi nhét thẳng vào tệp nhị phân. Sau đó thư viện không còn vai trò gì nữa.
| Linux và macOS | Windows | |
|---|---|---|
| Phần mở rộng | .a | .lib, hoặc .a với MinGW |
| Công cụ tạo | ar | lib.exe, hoặc ar với MinGW |
| Tên quy ước | libmath.a | math.lib, hoặc libmath.a |
| Cách gọi khi liên kết | -lmath | math.lib, hoặc -lmath |
| Định dạng bên trong | ar archive | Giống, khi dùng MinGW |
#Ba bước tạo
Cây thư mục
mathlib/
include/
mathlib.h
src/
hinhhoc.c
sohoc.c
build/
main.cinclude/mathlib.h
#ifndef MATHLIB_H
#define MATHLIB_H
#define PI 3.14159
double dt_hinh_tron(double r);
double cv_hinh_tron(double r);
long giai_thua(int n);
int uoc_chung_lon_nhat(int a, int b);
#endifsrc/sohoc.c
#include "mathlib.h"
static int tru(int a, int b) { return a - b; } /* noi bo, khong xuat ra */
long giai_thua(int n) {
long t = 1;
for (int i = 2; i <= n; ++i) t *= i;
return t;
}
int uoc_chung_lon_nhat(int a, int b) { ... }terminal
# Bước 1: dịch từng tệp nguồn thành tệp đối tượng
gcc -c -Iinclude src/hinhhoc.c -o build/hinhhoc.o
gcc -c -Iinclude src/sohoc.c -o build/sohoc.o
# Bước 2: đóng gói
ar rcs build/libmath.a build/hinhhoc.o build/sohoc.o
# Bước 3: xem kết quả
ls -l build/
-rw-r--r-- 1 DELL 197609 990 hinhhoc.o -rw-r--r-- 1 DELL 197609 2276 libmath.a -rw-r--r-- 1 DELL 197609 1021 sohoc.o
Makefile
Makefile
CC = gcc
CFLAGS = -std=c11 -Iinclude -Wall -Wextra -Wpedantic -O2
NGUON = $(wildcard src/*.c)
DOI_TUONG = $(patsubst src/%.c,build/%.o,$(NGUON))
build/libmath.a: $(DOI_TUONG)
ar rcs $@ $^
build/%.o: src/%.c include/mathlib.h | build
$(CC) $(CFLAGS) -c -o $@ $<
build:
mkdir -p build
sach:
rm -rf build
.PHONY: sach
# Chu y "| build": day la phu thuoc thu tu.
# No bao dam thu muc build ton tai truoc khi dich, nhung KHONG
# lam .o phai dich lai moi khi thu muc doi thoi diem sua.#Nhìn vào bên trong
terminal
# Liệt kê các tệp .o bên trong
ar t build/libmath.a
hinhhoc.o sohoc.o
# Xem bảng ký hiệu
nm build/libmath.a
hinhhoc.o: 000000000000002b T cv_hinh_tron 0000000000000000 T dt_hinh_tron sohoc.o: 0000000000000012 T giai_thua 0000000000000000 t tru 000000000000004c T uoc_chung_lon_nhat
ar t libmath.a # liet ke ten tep .o
ar tv libmath.a # kem kich thuoc va thoi diem
ar x libmath.a # GIAI NEN: lay lai cac tep .o ra thu muc hien tai
ar x libmath.a sohoc.o # chi lay mot tep
ar d libmath.a sohoc.o # xoa mot tep khoi thu vien
ar r libmath.a moi.o # them hoac thay the mot tep
nm libmath.a # ky hieu cua tung tep .o
nm --defined-only libmath.a # bo cac ky hieu chua dinh nghia
objdump -a libmath.a # dau muc cua tung thanh vien#Dùng thư viện
terminal
gcc -Iinclude main.c -Lbuild -lmath -o app.exe && ./app.exe
dt(2) = 12.56636 cv(2) = 12.56636 5! = 120
| Cờ | Nói với trình biên dịch |
|---|---|
| -Iinclude | Tìm tệp header trong thư mục include |
| -Lbuild | Tìm tệp thư viện trong thư mục build |
| -lmath | Liên kết với libmath.a hoặc libmath.so |
| -l:libmath.a | Liên kết đúng tệp này, không đoán tên |
| build/libmath.a | Chỉ tên tệp thẳng, không cần -L và -l |
#Trình liên kết lấy gì từ thư viện
# Cach do: dem so ky hieu that su vao trong chuong trinh
nm app.exe | grep -E 'dt_hinh_tron|cv_hinh_tron|giai_thua'
# Hoac de trinh bien dich chia nho gium:
gcc -ffunction-sections -fdata-sections -c src/*.c
gcc main.o -Wl,--gc-sections -Lbuild -lmath -o app
# -ffunction-sections moi ham vao mot phan doan rieng
# -fdata-sections moi bien vao mot phan doan rieng
# --gc-sections trinh lien ket xoa phan doan khong ai dung
#
# Ba co nay lam viec chia .o thanh nho tu dong. Rat dang bat
# trong ma nhung, noi tung KB deu quy. Bai 46.3 da noi.Tự làm thử
- Đóng gói hai tệp nguồn thành một thư viện tĩnh và chạy
ar tlên nó. - Chạy
nmvà xác định hàm nào làThàm nào làt. - Bỏ chữ
strongar rcsvà xem trình liên kết nói gì. - Giải nén thư viện bằng
ar xtrong một thư mục rỗng. - Chứng minh một hàm không ai gọi vẫn vào tệp nhị phân nếu nó cùng
.ovới hàm được gọi. - Bật
-ffunction-sectionsvà--gc-sections, đo lại kích thước.
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
- Tệp
.alà một kho lưu trữ chứa nguyên các tệp.o, cộng một mục lục ký hiệu. ar rcs:rthêm hoặc thay,ctạo mới im lặng,ssinh mục lục.nmhiệnTcho hàm công khai vàtcho hàmstatic. Đó là ranh giới API của thư viện.- Trình liên kết lấy cả tệp .o chứ không lấy từng hàm, nên hãy chia thư viện thành nhiều tệp nguồn nhỏ.
-lmathtìmlibmath.a, nên tên tệp bắt buộc phải có tiền tốlib.