Giới thiệu về Make
Make là một công cụ xây dựng (build tool) phổ biến được sử dụng để biên dịch và quản lý các dự án phần mềm. Nó đặc biệt hữu ích với các dự án có nhiều file nguồn, nơi mà việc xác định lại các file cần biên dịch lại khi có sự thay đổi là rất quan trọng.
Make hoạt động dựa trên một file cấu hình tên là Makefile, trong đó chứa các quy tắc xây dựng dự án. Khi bạn chạy lệnh make, công cụ này sẽ đọc file Makefile và thực hiện các lệnh tương ứng để xây dựng mục tiêu (target) bạn yêu cầu.
Cấu trúc cơ bản của một Makefile
Định dạng cơ bản của một quy tắc trong Makefile như sau:
<target>: <prerequisites>
[TAB]command
- Target: là file hoặc tác vụ bạn muốn tạo ra.
- Prerequisites: là các file hoặc điều kiện cần thiết để tạo ra target.
- Command: là các lệnh shell thực hiện việc xây dựng target.
Ví dụ:
result.txt: source.txt
[TAB]cp source.txt result.txt
Trong ví dụ trên, nếu file source.txt thay đổi hoặc không tồn tại, lệnh cp sẽ được thực thi để cập nhật file result.txt.
Target giả lập (Phony Targets)
Các target như clean không đại diện cho một file cụ thể mà là một tác vụ, được gọi là target giả lập.
.PHONY: clean
clean:
[TAB]rm *.o
Khai báo .PHONY đảm bảo rằng lệnh make clean luôn được thực thi, bất kể có file nào tên là clean tồn tại hay không.
Thông tin về biến và hàm trong Makefile
Makefile hỗ trợ sử dụng biến để lưu trữ giá trị:
SRC = main.c utils.c
OBJ = $(SRC:.c=.o)
Trong đó:
:=- Gán giá trị tại thời điểm định nghĩa.=- Gán giá trị và cho phép mở rộng sau này.?=- Chỉ gán nếu biến chưa được định nghĩa.+=- Thêm giá trị vào biến đã có.
Một số biến tự động (Automatic Variables)
$@: Tên của target hiện tại.$<: Tên của prerequisite đầu tiên.$^: Danh sách tất cả các prerequisite.
Ví dụ:
%.o: %.c
[TAB]$(CC) -c $< -o $@
Thực thi nhiều lệnh trong một rule
Mỗi dòng lệnh trong một rule được thực thi trong một shell riêng biệt. Nếu bạn muốn chia sẻ trạng thái giữa các lệnh, hãy dùng dấu \ để nối dòng hoặc thêm .ONESHELL:.
.ONESHELL:
build:
[TAB]cd src
[TAB]gcc -c main.c
Điều kiện và vòng lặp
Makefile hỗ trợ cú pháp Bash để thực hiện điều kiện và vòng lặp:
ifeq ($(DEBUG), yes)
CFLAGS += -g
else
CFLAGS += -O2
endif
Vòng lặp:
LIST = one two three
all:
[TAB]for item in $(LIST); do \
echo $$item; \
done
Hàm trong Makefile
Makefile hỗ trợ một số hàm để xử lý chuỗi và file:
$(wildcard pattern): Lấy danh sách file khớp với mẫu.$(subst from,to,text): Thay thế chuỗi.$(patsubst pattern,replacement,text): Thay thế theo mẫu.
Ví dụ:
SRC = $(wildcard *.c)
OBJ = $(patsubst %.c,%.o,$(SRC))
Ví dụ hoàn chỉnh
Makefile cho một dự án C đơn giản:
CC = gcc
CFLAGS = -Wall -Wextra
SRC = main.c utils.c
OBJ = $(SRC:.c=.o)
EXEC = myapp
all: $(EXEC)
$(EXEC): $(OBJ)
[TAB]$(CC) $(CFLAGS) $(OBJ) -o $@
%.o: %.c
[TAB]$(CC) $(CFLAGS) -c $< -o $@
clean:
[TAB]rm -f $(OBJ) $(EXEC)
.PHONY: all clean