Makefile nâng cao: Mẹo, thủ thuật và các thực tiễn tốt nhất cho dự án Python
By hientd, at: 09:52 Ngày 04 tháng 1 năm 2024
Thời gian đọc ước tính: __READING_TIME__ minutes


Trong bài đăng đầu tiên, chúng ta đã tìm hiểu các kiến thức cơ bản về Makefile và cách sử dụng nó để tự động hóa các tác vụ đơn giản trong các dự án Python. Bây giờ, chúng ta sẽ nâng cao hơn nữa. Bài đăng này tập trung vào các kỹ thuật Makefile nâng cao, chẳng hạn như sử dụng biến, mục tiêu ảo, điều kiện và thực thi song song, để tạo ra các luồng tự động hóa hiệu quả và dễ bảo trì.
Tại sao cần vượt qua những kiến thức cơ bản?
Mặc dù một Makefile đơn giản có thể xử lý các tác vụ đơn giản, nhưng các kỹ thuật nâng cao cung cấp:
- Khả năng tái sử dụng tốt hơn với các biến và mẫu động.
- Nâng cao hiệu quả bằng cách sử dụng thực thi song song.
- Các luồng công việc được tổ chức tốt hơn với mục tiêu ảo và quản lý phụ thuộc.
- Tính linh hoạt cao hơn với các điều kiện và hàm.
1. Sử dụng Biến để tăng khả năng tái sử dụng
Biến giúp Makefile của bạn thích ứng và giảm sự lặp lại. Bạn có thể định nghĩa đường dẫn, lệnh và cờ một lần và tái sử dụng chúng trong nhiều mục tiêu.
Ví dụ:
# Định nghĩa biến
PYTHON = python3
SRC_DIR = src
TEST_DIR = tests
# Sử dụng biến
test:
$(PYTHON) -m pytest $(TEST_DIR)/
format:
$(PYTHON) -m black $(SRC_DIR)/
lint:
$(PYTHON) -m flake8 $(SRC_DIR)/ $(TEST_DIR)/
Lợi ích:
- Nếu bạn cần thay đổi trình thông dịch Python hoặc cấu trúc thư mục, hãy cập nhật nó ở một nơi.
2. Tổ chức tác vụ với Mục tiêu ảo
Mục tiêu ảo không được liên kết với các tệp và được sử dụng để nhóm hoặc tổ chức các tác vụ. Khai báo chúng bằng .PHONY
để tránh xung đột.
Ví dụ:
.PHONY: all clean
# Nhóm nhiều tác vụ
all: install test format lint
clean:
find . -name '__pycache__' -exec rm -rf {} + \
&& find . -name '*.pyc' -exec rm -f {} +
Lợi ích:
- Đảm bảo
make
không vô tình liên kết các mục tiêu với các tệp cùng tên.
- Làm cho luồng công việc được tổ chức hơn.
3. Tối ưu hóa việc xây dựng bằng Phụ thuộc
Phụ thuộc đảm bảo rằng các tác vụ chỉ chạy khi cần thiết. Bạn có thể chỉ định tệp hoặc tác vụ nào mà một mục tiêu phụ thuộc vào.
Ví dụ:
output.txt: input.txt script.py
$(PYTHON) script.py input.txt > output.txt
Cách hoạt động:
- Nếu
input.txt
hoặcscript.py
thay đổi,output.txt
sẽ được tạo lại.
- Tiết kiệm thời gian bằng cách tránh các lần thực thi không cần thiết.
4. Sử dụng Điều kiện để tăng tính linh hoạt
Điều kiện cho phép bạn định nghĩa hành vi dựa trên biến hoặc trạng thái hệ thống.
Ví dụ:
ifeq ($(ENV), production)
RUN_FLAGS = --optimize
else
RUN_FLAGS = --debug
endif
run:
$(PYTHON) app.py $(RUN_FLAGS)
Lợi ích:
- Điều chỉnh các tác vụ cho các môi trường khác nhau như phát triển và sản xuất.
5. Tăng tốc độ tác vụ với Thực thi song song
Đối với các tác vụ không phụ thuộc lẫn nhau, make
có thể thực thi chúng song song bằng cờ -j
.
Ví dụ:
make -j4
Điều này chạy tối đa 4 tác vụ cùng một lúc, tăng tốc độ luồng công việc như:
- Chạy nhiều trình kiểm tra hoặc kiểm thử.
- Xây dựng các thành phần độc lập của một dự án.
6. Gỡ lỗi và khắc phục sự cố
Sử dụng cờ --debug
để khắc phục sự cố với Makefile của bạn. Nó cung cấp đầu ra chi tiết về các tác vụ và phụ thuộc đang được thực thi.
Ví dụ:
make --debug=v test
Thực tiễn tốt nhất cho Makefile nâng cao
- Giữ cho nó mô đun: Chia các Makefile lớn thành các phần nhỏ hơn, có thể tái sử dụng bằng cách bao gồm các Makefile khác.
include common.mk
- Sử dụng chú thích: Tài liệu hóa các mục tiêu để giúp Makefile của bạn dễ hiểu.
# Kiểm tra mã nguồn
lint:
$(PYTHON) -m flake8 src/ tests/
- Kiểm thử thường xuyên: Xác nhận rằng các mục tiêu hoạt động như dự định để tránh những bất ngờ trong quá trình tự động hóa.
Kết luận
Với các kỹ thuật Makefile nâng cao này, bạn có thể biến một tệp tự động hóa cơ bản thành một công cụ mạnh mẽ để quản lý các luồng công việc phức tạp trong các dự án Python. Biến, mục tiêu ảo, phụ thuộc và thực thi song song mang lại hiệu quả, khả năng tái sử dụng và tính linh hoạt cho quy trình phát triển của bạn.
Trong bài đăng cuối cùng của loạt bài này, chúng ta sẽ khám phá ứng dụng thực tế của Makefile, bao gồm tích hợp nó với Docker, đường dẫn CI/CD và các trường hợp sử dụng cụ thể của Python.