Các Điều Kiện Trong Makefile
Tổng quan
Điều kiện trong Makefile cho phép bạn quyết định xem một phần nội dung có được thực thi hay bị bỏ qua dựa trên giá trị của biến. Điều kiện có thể so sánh giá trị của một biến với giá trị của một biến khác, hoặc so sánh giá trị của biến với một chuỗi hằng số. Các chỉ thị điều khiển ảnh hưởng đến nội dung mà make thực sự thấy trong Makefile, do đó không thể sử dụng để kiểm soát các thao tác trong quá trình thực thi.
Dưới đây là một ví dụ đơn giản về Makefile sử dụng chỉ thị điều kiện:
# Định nghĩa biến
DEBUG = yes
# Sử dụng chỉ thị điều kiện
ifeq ($(DEBUG),yes)
CFLAGS = -g
else
CFLAGS = -O2
endif
# Mục tiêu mặc định
all: chuong_trinh
# Biên dịch chương trình
chuong_trinh: main.c
gcc $(CFLAGS) -o chuong_trinh main.c
# Dọn dẹp các tệp đã tạo
clean:
rm -f chuong_trinh
Trong ví dụ trên, tùy thuộc vào giá trị của biến `DEBUG`, các tùy chọn biên dịch `CFLAGS` khác nhau sẽ được chọn. Nếu giá trị của `DEBUG` là "yes", thì `CFLAGS` được đặt thành "-g", ngược lại là "-O2". Việc đánh giá điều kiện này xảy ra khi phân tích Makefile, chứ không phải trong quá trình thực hiện bước biên dịch.
Ví dụ về điều kiện
Ví dụ điều kiện này cho make biết khi nào biến BIEN_DICH là 'gcc' thì sử dụng một bộ thư viện, và ngược lại sẽ sử dụng bộ thư viện khác. Nó thực hiện việc kiểm soát dòng công thức nào sẽ được sử dụng trong quy tắc. Kết quả là, việc truyền 'BIEN_DICH=gcc' làm tham số cho make không chỉ thay đổi trình biên dịch được sử dụng mà còn thay đổi thư viện được liên kết.
thu_viet_gcc = -lgnu
thu_viet_thuong =
dich_vu: $(doi_tuong)
ifeq ($(BIEN_DICH),gcc)
$(BIEN_DICH) -o dich_vu $(doi_tuong) $(thu_viet_gcc)
else
$(BIEN_DICH) -o dich_vu $(doi_tuong) $(thu_viet_thuong)
endif
Điều kiện này sử dụng ba chỉ thị: một ifeq, một else và một endif.
- Chỉ thị ifeq bắt đầu điều kiện và chỉ định điều kiện. Nó chứa hai tham số được phân tách bằng dấu phẩy và được đặt trong ngoặc đơn. Thay thế biến được thực hiện trên hai tham số, sau đó chúng được so sánh. Các dòng Makefile sau ifeq sẽ được thực thi khi hai tham số khớp, nếu không chúng sẽ bị bỏ qua.
- Chỉ thị else khiến các dòng tiếp theo được thực thi khi điều kiện trước đó thất bại. Trong ví dụ trên, điều kiện này có nghĩa là chỉ lệnh liên kết thay thế thứ hai sẽ được sử dụng khi lệnh liên kết thay thế đầu tiên không được sử dụng. Việc có else trong điều kiện là tùy chọn.
- Chỉ thị endif kết thúc điều kiện. Mỗi điều kiện phải kết thúc bằng endif. Văn bản Makefile không điều kiện sẽ xuất hiện sau đó.
Nếu giá trị của biến BIEN_DICH là 'gcc', hiệu quả của ví dụ trên như sau:
dich_vu: $(doi_tuong)
$(BIEN_DICH) -o dich_vu $(doi_tuong) $(thu_viet_gcc)
Khi biến BIEN_DICH có bất kỳ giá trị nào khác, hiệu quả như sau:
dich_vu: $(doi_tuong)
$(BIEN_DICH) -o dich_vu $(doi_tuong) $(thu_viet_thuong)
Cũng có thể đạt được kết quả tương tự bằng cách điều kiện hóa việc gán biến, sau đó sử dụng biến một cách vô điều kiện:
thu_viet_gcc = -lgnu
thu_viet_thuong =
ifeq ($(BIEN_DICH),gcc)
tap_thu_viet=$(thu_viet_gcc)
else
tap_thu_viet=$(thu_viet_thuong)
endif
dich_vu: $(doi_tuong)
$(BIEN_DICH) -o dich_vu $(doi_tuong) $(tap_thu_viet)
Cú pháp câu lệnh điều kiện
Đây là tóm tắt các khái niệm quan trọng liên quan đến cú pháp và cách sử dụng chỉ thị điều kiện trong Makefile:
- Cú pháp điều kiện đơn giản:
chi_dieu_kien van_ben_dung_khi_dung ket_thuc_dieu_kien
Nếu điều kiện đúng, phần `van_ben_dung_khi_dung` sẽ được thực thi; nếu không, phần này sẽ bị bỏ qua.
- Cú pháp điều kiện phức tạp:
chi_dieu_kien van_ben_dung_khi_dung khong van_ben_dung_khi_sai ket_thuc_dieu_kien
Hoặc nhiều mệnh đề `không`:
chi_dieu_kien_mot van_ben_dung_khi_mot_dung khong chi_dieu_kien_hai van_ben_dung_khi_hai_dung khong van_ben_dung_khi_va_mot_va_hai_sai ket_thuc_dieu_kien
Khi điều kiện đúng, phần `van_ben_dung_khi_dung` được thực thi; nếu không, phần `van_ben_dung_khi_sai` hoặc nội dung trong các mệnh đề `khác` khác được thực thi.
- Các loại chỉ thị điều kiện:
- `ifeq (thamso1, thamso2)`
- `ifneq (thamso1, thamso2)`
- `ifdef ten_bien`
- `ifndef ten_bien`
Các chỉ thị này kiểm tra các điều kiện khác nhau. Điều kiện có thể chứa tham chiếu biến, sẽ được mở rộng trước khi so sánh.
- Thử nghiệm biến điều kiện:
- `ifeq` và `ifneq` được sử dụng để so sánh hai tham số có bằng nhau hay không bằng nhau.
- `ifdef` kiểm tra một biến đã được định nghĩa và không rỗng.
- `ifndef` kiểm tra một biến không được định nghĩa hoặc rỗng.
- Mở rộng biến trong điều kiện:
Tham chiếu biến trong điều kiện sẽ được mở rộng. Ví dụ: `$(strip $(bien))` được sử dụng để kiểm tra biến `bien` có rỗng không.
- Tác động của điều kiện:
Điều kiện ảnh hưởng đến việc make sử dụng những dòng nào trong Makefile. Nếu điều kiện đúng, make đọc phần `van_ben_dung_khi_dung`; nếu điều kiện sai, các dòng này sẽ bị bỏ qua hoàn toàn.
- Thời điểm đánh giá điều kiện:
Điều kiện được đánh giá khi đọc Makefile, do đó không thể sử dụng biến tự động trong thử nghiệm điều kiện, vì chúng chỉ được định nghĩa khi thực hiện quy tắc.
- Nesting và include trong điều kiện:
Điều kiện có thể lồng vào nhau. `include` có thể được sử dụng trong điều kiện, nhưng không được phép bắt đầu điều kiện trong một Makefile và kết thúc trong một Makefile khác.
Điều kiện kiểm tra cờ
Phần này giới thiệu cách sử dụng chỉ thị điều kiện cùng với biến `THAM_SO_MAKE` và hàm `tim_chuoi` để kiểm tra các cờ của lệnh `make`, chẳng hạn như cờ `-t`. Điều này rất hữu ích trong trường hợp `touch` không đủ để làm cho tệp trông mới nhất.
`THAM_SO_MAKE` đặt tất cả các tùy chọn chữ cái (ví dụ: `-t`) vào từ đầu tiên, nếu không có tùy chọn chữ cái nào được cung cấp, thì từ đó sẽ là rỗng. Để xử lý tình huống này thuận tiện hơn, hãy thêm một giá trị ở đầu để đảm bảo có một từ, ví dụ: '-$(THAM_SO_MAKE)'.
Hàm `tim_chuoi` được sử dụng để xác định xem một chuỗi có xuất hiện trong một chuỗi khác không. Để kiểm tra cờ `-t`, hãy đặt 't' làm chuỗi đầu tiên và từ đầu tiên của `THAM_SO_MAKE` làm chuỗi khác.
Ví dụ dưới đây cho thấy cách thiết lập sử dụng 'chay_thu_viet -t' để hoàn thành quá trình đánh dấu tệp lưu trữ là mới nhất:
tap_luu_tru.a: ...
ifneq (,$(findstring t,$(firstword -$(THAM_SO_MAKE))))
+touch tap_luu_tru.a
+chay_thu_viet -t tap_luu_tru.a
else
chay_thu_viet tap_luu_tru.a
endif
Trong ví dụ này, nếu cờ `-t` có trong `THAM_SO_MAKE`, thì `touch tap_luu_tru.a` và `chay_thu_viet -t tap_luu_tru.a` sẽ được thực thi, nếu không thì thực thi `chay_thu_viet tap_luu_tru.a`. Tiền tố `+` đánh dấu các công thức này là "đệ quy" để chúng sẽ được thực thi, ngay cả khi sử dụng cờ `-t`.