Bỏ qua điều hướng, tới nội dung chính
Học C
Bài 37.226 phút đọc

Biến, biến tự động, quy tắc mẫu

Sau bài này bạn sẽ làm được

  • Phân biệt :=, =, ?=, +=
  • Dùng biến tự động $@, $<, $^
  • Viết quy tắc mẫu %.o từ %.c
  • Dùng wildcard và thay thế hậu tố

Makefile ở bài trước lặp lại tên tệp khắp nơi. Bài này thay chúng bằng biến và một quy tắc mẫu duy nhất, để thêm một tệp .c vào dự án không cần sửa Makefile.

#Biến và bốn cách gán

Cú phápNghĩaDùng khi
:=Gán ngay lập tức, tính giá trị một lầnMặc định, dùng cái này
=Gán lười, tính lại mỗi lần dùngHiếm, khi cần trì hoãn
?=Gán nếu chưa có giá trịCho phép ghi đè từ dòng lệnh
+=Nối thêm vào giá trị hiện cóThêm cờ theo cấu hình
Bốn cách gán
CC       := gcc                  # ngay lap tuc
CSTD     := -std=c17
WARN     := -Wall -Wextra
CFLAGS   := $(CSTD) $(WARN)       # tinh NGAY, thanh "-std=c17 -Wall -Wextra"

OPTLEVEL ?= -O0                  # dat -O0 NEU chua ai dat
# make OPTLEVEL=-O2  -> dong lenh thang, khong bi ghi de

CFLAGS   += -Iinclude            # noi them, thanh "... -Iinclude"
terminal
make OPTLEVEL=-O2 xem
FILES = a.c b.c c.c
OBJS  = a.o b.o c.o

#Biến tự động

BiếnNghĩa
$@Tên mục tiêu
$<Phụ thuộc đầu tiên
$^Tất cả phụ thuộc
$?Các phụ thuộc mới hơn mục tiêu
$*Phần khớp % trong quy tắc mẫu
Biến tự động trong một quy tắc
build/%.o: src/%.c
	@echo "muc tieu  $$@ = $@"
	@echo "phu thuoc dau $$< = $<"
	@echo "moi phu thuoc $$^ = $^"
	gcc -std=c17 -Iinclude -c $< -o $@
terminal
make build/toan.o
muc tieu  $@ = build/toan.o
phu thuoc dau $< = src/toan.c
moi phu thuoc $^ = src/toan.c
gcc -std=c17 -Iinclude -c src/toan.c -o build/toan.o

#wildcard và thay hậu tố

Tự tìm tệp nguồn
# $(wildcard mau): tim file khop mau NGAY luc doc Makefile
SRCS := $(wildcard src/*.c)
# -> src/main.c src/toan.c src/db.c ...

# $(BIEN:cu=moi): thay hau to
OBJS := $(SRCS:src/%.c=build/%.o)
# -> build/main.o build/toan.o build/db.o ...

DEPS := $(OBJS:.o=.d)
# -> build/main.d build/toan.d ...
terminal
make xem
FILES = a.c b.c c.c
OBJS  = a.o b.o c.o

#Quy tắc mẫu

Quy tắc mẫu
Một quy tắc dùng % làm ký tự đại diện, áp dụng cho mọi tệp khớp mẫu. build/%.o: src/%.c nghĩa là "để tạo bất kỳ build/x.o nào, cần src/x.ctương ứng".
Một quy tắc mẫu thay cho N quy tắc
# MOT quy tac nay ap dung cho MOI cap src/*.c -> build/*.o
build/%.o: src/%.c
	@mkdir -p $(dir $@)          # tao thu muc build neu chua co
	$(CC) $(CFLAGS) -c $< -o $@

# % khop phan giua. Voi build/toan.o:
#   % = "toan"
#   phu thuoc = src/toan.c
#   $< = src/toan.c, $@ = build/toan.o

#Gộp lại

Makefile với biến và quy tắc mẫu
CC       := gcc
CFLAGS   := -std=c17 -Wall -Wextra -Iinclude
SRC_DIR  := src
BUILD    := build
TARGET   := $(BUILD)/app.exe

SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD)/%.o)

.PHONY: all clean
all: $(TARGET)

$(TARGET): $(OBJS)
	$(CC) $^ -o $@
	@echo "==> Da build: $@"

$(BUILD)/%.o: $(SRC_DIR)/%.c
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	rm -rf $(BUILD)
terminal
make
gcc -std=c17 -Wall -Wextra -Iinclude -c src/main.c -o build/main.o
gcc -std=c17 -Wall -Wextra -Iinclude -c src/toan.c -o build/toan.o
gcc build/main.o build/toan.o -o build/app.exe
==> Da build: build/app.exe

Tự làm thử

  1. Viết lại Makefile của bạn dùng wildcard và một quy tắc mẫu.
  2. Thêm một tệp .c mới và xác nhận Makefile không cần sửa.
  3. Dùng ?= cho mức tối ưu và ghi đè bằng make OPTLEVEL=-O2.
  4. In ra $@, $<, $^ trong một quy tắc và đối chiếu với tên tệp thật.
  5. Thử gán CFLAGS = $(CFLAGS) -Wall với = và quan sát Make treo.
  6. Chạy make -p và tìm quy tắc ngầm dịch .c thành .o.

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

  • Bốn cách gán: := ngay lập tức (mặc định), = lười, ?= nếu chưa có, += nối thêm.
  • Biến tự động $@ là mục tiêu, $< là phụ thuộc đầu, $^ là mọi phụ thuộc.
  • wildcard tự tìm tệp, thay hậu tố sinh danh sách .o từ danh sách .c.
  • Một quy tắc mẫu build/%.o: src/%.c thay cho một quy tắc riêng cho mỗi tệp.
  • Kết hợp lại cho một Makefile không bao giờ phải sửa khi thêm tệp nguồn.