Bài 37.328 phút đọc
Theo dõi header tự động
Sau bài này bạn sẽ làm được
- Giải thích vì sao sửa header không kích hoạt dựng lại
- Dùng -MMD -MP để sinh và nạp phụ thuộc
- Đọc một file .d GCC sinh ra
- Dùng make -j để dựng song song
Makefile ở bài trước có một lỗ hổng nguy hiểm: sửa một tệp header không kích hoạt dịch lại. Hậu quả là bạn chạy chương trình với bố cục struct cũ và mới lẫn lộn, một trong những lỗi khó hiểu nhất. Hai cờ chữ chữa nó.
#Bug khó hiểu nhất
Makefile thiếu theo dõi header
$(BUILD)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
# Quy tac chi noi: build/x.o phu thuoc src/x.c.
# No KHONG noi gi ve cac .h ma x.c include.
# Nen khi ban sua include/toan.h:
# - src/main.c KHONG doi -> Make khong dich lai main.o
# - nhung main.o dua tren toan.h CUterminal
# Makefile khong co -MMD, sua header
touch include/toan.h && make
mingw32-make: 'app_sai.exe' is up to date.
#-MMD -MP
Thêm hai cờ và một dòng
# 1. Them -MMD -MP vao CFLAGS
CFLAGS := -std=c17 -Wall -Wextra -Iinclude -MMD -MP
# 2. Tinh danh sach file .d
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD)/%.o)
DEPS := $(OBJS:.o=.d)
# 3. Nap cac file .d o cuoi Makefile
-include $(DEPS)| Cờ | Làm gì |
|---|---|
| -MMD | Khi dịch, sinh thêm tệp .d liệt kê các header mà tệp .c include (bỏ header hệ thống) |
| -MP | Thêm một mục tiêu giả rỗng cho mỗi header, tránh lỗi khi xoá header |
| -include | Nạp các tệp .d; dấu - để không lỗi khi tệp .d chưa tồn tại |
#Đọc tệp .d
terminal
make && cat build/main.d
build/main.o: src/main.c include/toan.h include/toan.h:
#Chứng minh
terminal
# Voi -MMD -MP: sua header -> dich lai cac file phu thuoc
touch include/toan.h && make
gcc -std=c17 -Wall -Wextra -Iinclude -MMD -MP -c src/main.c -o build/main.o gcc -std=c17 -Wall -Wextra -Iinclude -MMD -MP -c src/toan.c -o build/toan.o gcc build/main.o build/toan.o -o build/app.exe ==> Da build: build/app.exe
Không theo dõi header
CFLAGS := -std=c17 -Iinclude
$(BUILD)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
# Sua header -> KHONG dich lai -> bug bo cuc struct.
# "Chua" bang make clean moi lan -> dich lai het, cham.
Có -MMD -MP
CFLAGS := -std=c17 -Iinclude -MMD -MP
$(BUILD)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
-include $(DEPS)
# Sua header -> dich lai DUNG cac file phu thuoc no.
# Khong bao gio can make clean.
#Dựng song song
terminal
# -j: dung nhieu luong, dich cac file doc lap cung luc
make -j8
# dung het so CPU (Linux/macOS)
make -j$(nproc)
Tự làm thử
- Thêm
-MMD -MPvào Makefile của bạn và mở một tệp.dđược sinh ra. - Sửa một header và xác nhận đúng các tệp phụ thuộc được dịch lại.
- Bỏ
-MP, xoá một header, và quan sát lỗiNo rule to make target. - So
-MDvà-MMD: đếm số dòng trong tệp.dmỗi cách sinh ra. - Dựng một dự án nhiều tệp với
-j8và đo chênh lệch thời gian. - Cố tình bỏ một phụ thuộc và xem
make -jcó lộ ra lỗi thứ tự không.
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
- Thiếu theo dõi header là bug khó hiểu nhất của Make: sửa header không kích hoạt dịch lại.
-MMDsinh tệp.dliệt kê header của bạn,-MPthêm mục tiêu giả để tránh lỗi khi xoá header.- Tệp
.dchính là một quy tắc Make;-includenạp chúng vào đồ thị phụ thuộc. - Ba dòng
-MMD -MP,DEPS,-includenên có trong mọi dự án C. make -jdựng song song và là phép thử tính đúng của Makefile; dựng tuần tự khi cần đọc lỗi.