1. What is Linux make command?
Lệnh make trong Linux được sử dụng để xây dựng và duy trì các nhóm chương trình và file từ mã nguồn. Trong Linux, đây là một trong những lệnh được sử dụng thường xuyên nhất bởi các nhà phát triển. Nó giúp các nhà phát triển cài đặt và biên dịch nhiều tiện ích từ terminal. Hơn nữa, nó xử lý quá trình biên dịch của các dự án lớn. Nó tiết kiệm thời gian biên dịch.
Mục đích chính của lệnh make là chia một chương trình lớn thành các phần và kiểm tra xem liệu chúng có cần phải được biên dịch lại hay không. Nó cũng cung cấp các lệnh cần thiết để biên dịch lại chúng.
Trong phần này, chúng tôi sẽ sử dụng các chương trình C++ vì ngôn ngữ lập trình C++ là một ngôn ngữ hướng đối tượng, nhưng bạn có thể sử dụng bất kỳ ngôn ngữ nào được cài đặt trên máy của bạn. Nó không chỉ giới hạn trong việc biên dịch các chương trình mà chúng ta có thể sử dụng nó để thực hiện các tác vụ khác.
2. How make command works?
Lệnh make trong Linux nhận các tham số đích để biên dịch các chương trình từ mã nguồn. Các đối số này được chỉ định trong file ‘Makefile’. File makefile chứa các mục tiêu cùng với các hoạt động liên quan đến các mục tiêu này.
Khi thực thi lệnh make, nó sẽ tìm kiếm file makefile và quét nó để tìm mục tiêu và truy cập các phụ thuộc của nó. Nếu các phụ thuộc không được chỉ định, nó sẽ tìm kiếm phụ thuộc và sẽ xây dựng nó. Sau khi các phụ thuộc được xây dựng, nó sẽ xây dựng mục tiêu chính.
Ví dụ, nếu chúng ta muốn chỉ thay đổi một file nguồn và chạy lệnh make, thì nó chỉ biên dịch file đối tượng liên quan đến file nguồn đó. Điều này sẽ tiết kiệm rất nhiều thời gian trong quá trình biên dịch cuối cùng của dự án.
3. What is Makefile?
Makefile là một file đặc biệt chứa các lệnh shell được tạo ra để duy trì dự án. Nó chứa các mục tiêu và lệnh cho việc thực thi. Chúng ta không được phép tạo nhiều hơn một Makefile. Để tốt hơn, chúng ta nên tạo một thư mục riêng để chứa Makefile.
Makefile lưu trữ các file mới nhất, vì vậy chỉ cập nhật những file cần thiết. Nếu chúng ta có một chương trình lớn với nhiều file nguồn, chúng ta phải biên dịch lại tất cả các file phụ thuộc. Vì vậy, quá trình này có thể mất rất nhiều thời gian.
Makefile có một danh sách các tiêu chuẩn để hệ thống hiểu rõ các lệnh chúng ta muốn thực hiện. Các tiêu chuẩn này được phân thành hai phần và được tách ra bằng một dòng mới. Dòng đầu tiên là dòng phụ thuộc, và các dòng tiếp theo được coi là các hành động hoặc lệnh. Các lệnh được phân tách bằng một tab ở một dòng mới.
Các phụ thuộc chỉ định mối quan hệ giữa mỗi file với các file nguồn. Và mục tiêu là một file thực thi, được tạo ra sau khi thực thi lệnh make.
4. Options
Lệnh make cung cấp nhiều tùy chọn (option) để làm cho nó trở nên cụ thể hơn. Một số tùy chọn quan trọng như sau:
- -b, -m: Các tùy chọn này được sử dụng để bỏ qua tính tương thích cho các phiên bản khác nhau của lệnh make.
- -B, –always-make: Các tùy chọn này được sử dụng để tạo ra tất cả các mục tiêu một cách vô điều kiện.
- -C dir, –directory=dir: Các tùy chọn này được sử dụng để thay đổi thư mục trước khi thực hiện file makefile.
- -d: Nó được sử dụng để in thông tin gỡ lỗi.
- –debug[=FLAGS]: Nó được sử dụng để in thông tin gỡ lỗi cùng với xử lý thông thường. Nếu chúng ta bỏ qua cờ, thì nó sẽ hiển thị kết quả tương tự như tùy chọn ‘-d’.
- -e, –environment-overrides: Nó được sử dụng để cung cấp biến được lấy từ môi trường ưu tiên hơn cho makefile.
- -f file, –file=file, –makefile=FILE: Nó được sử dụng để sử dụng một file như là một makefile.
- -i, –ignore-errors: Tùy chọn ‘-i’ được sử dụng để bỏ qua tất cả các lỗi trong các lệnh.
- -I dir, –include-dir=dir: Được sử dụng để chỉ định thư mục để tìm kiếm Makefile được chỉ định. Nếu chúng ta chỉ định nhiều tùy chọn ‘-I’, nó sẽ tìm kiếm trong nhiều thư mục theo thứ tự được chỉ định.
- -j [jobs], –jobs[=jobs]: Được sử dụng để chỉ định số lượng công việc được thực hiện đồng thời. Nếu chúng ta cung cấp nhiều tùy chọn ‘-j’, chỉ tùy chọn cuối cùng sẽ được sử dụng. Nếu chúng ta không chỉ định số lượng công việc, nó sẽ không giới hạn số lượng công việc được thực hiện đồng thời.
- -k, –keep-going: Được sử dụng để tiếp tục chương trình nếu gặp lỗi.
- -l [load], –load-average[=load]: Được sử dụng để chỉ định rằng không có tác vụ mới nào được bắt đầu nếu các tác vụ khác đang trong hàng đợi và trung bình tải được giảm xuống đến mức tối thiểu.
- -n, –just-print, –dry-run, –recon: Được sử dụng để hiển thị các lệnh sẽ được chạy mà không thực sự thực hiện chúng.
- -o file, –old-file=file, –assume-old=file: Được sử dụng để đảm bảo rằng make sẽ không tái tạo file nếu file đó cũ hơn các phụ thuộc của nó.
- -O[type], –output-sync[=type]: Được sử dụng để xác nhận đầu ra của mỗi tác vụ được tổ chức cùng nhau thay vì đầu ra xen kẽ của các tác vụ khác. Nó hữu ích cho xử lý nhiều công việc với tùy chọn ‘-j’.
- -p, –print-data-base: Được sử dụng để in ra cơ sở dữ liệu được tạo ra sau khi đọc các file Makefile. Nó cũng hữu ích để in ra thông tin phiên bản khi được sử dụng với tùy chọn ‘-v’. Để in ra cơ sở dữ liệu mà không cố gắng tạo lại bất kỳ file nào, thực thi lệnh như sau:
make -p -f/dev/null.
- -q: được sử dụng trong chế độ câu hỏi. Nó không chạy bất kỳ lệnh nào hoặc in bất kỳ thứ gì. Nó chỉ trả về mã thoát bằng không nếu mục tiêu đã được đồng bộ hóa trước đó; nếu không, nó sẽ hiển thị một mã thoát khác không bằng không.
- -r: được sử dụng để loại bỏ việc sử dụng các quy tắc ngầm định được tích hợp sẵn.
- -R: hữu ích nếu chúng ta không muốn định nghĩa bất kỳ biến tích hợp sẵn nào.
- –silent, –quiet : được gọi là hoạt động im lặng. Nó hạn chế in các lệnh khi chúng được thực thi.
- -S: được sử dụng để hủy bỏ hiệu ứng của tù -k, –keep-going.
- -t: được sử dụng để chạm vào tập tin thay vì chạy các lệnh của chúng.
- -trace’ được sử dụng để theo dõi sự sắp xếp của mỗi mục tiêu.
- -v: được sử dụng để in phiên bản của tiện ích make đã được cài đặt. Ngoài ra, nó hiển thị một danh sách các tác giả, bản quyền và một số thông báo liên quan đến tiện ích make.
- -w: được sử dụng để theo dõi một tin nhắn in chứa thư mục làm việc trước và sau khi xử lý khác. Nó hữu ích để theo dõi các lỗi từ cấu trúc phức tạp của lệnh make đệ quy.
- –no-print-directory được sử dụng để tắt -w.
- –what-if = file, –new-file = file, –assume-new = file: giả vờ rằng tập tin mục tiêu vừa được sửa đổi.
- –warn-undefined-variables: được sử dụng để cảnh báo rằng một biến chưa được xác định được tham chiếu.
Tạo một Makefile.
Makefile không bị giới hạn trong việc sử dụng các ngôn ngữ lập trình cụ thể. Bạn có thể sử dụng Makefile để quản lý các file Python hoặc Bash. Chúng ta có thể tạo một chương trình đơn giản bằng Python và sử dụng make để biên dịch và thực thi chương trình đó.
Hãy tạo một file có tên hello.py
với nội dung sau đây:
print("Hello, world!")
Sau đó, tạo một file Makefile
với nội dung sau đây:
all: hello
hello:
python3 hello.py
Hoặc sử dụng với bash để cài đặt tree.
all: hello
hello:
sudo apt-get update
sudo apt-get install tree -y
tree --version
Trong Makefile này, all
và hello
được coi là các targets, và python hello.py
được coi là một action cho target hello
. Câu lệnh all: hello
có nghĩa là khi chúng ta chạy make all
, nó sẽ thực thi target hello
.
Giờ đây, chạy lệnh make
trong thư mục chứa Makefile
để biên dịch và thực thi chương trình Python:
$ make
python3 hello.py
Hello, world!
Dưới đây là một ví dụ với nhiều hành động hơn để kiểm tra:
all: create_dir compile_program clean
create_dir:
mkdir -p bin obj
compile_program:
g++ -c src/main.cpp -o obj/main.o
g++ -c src/utils.cpp -o obj/utils.o
g++ obj/main.o obj/utils.o -o bin/myprogram
clean:
rm -rf obj/*
Trong ví dụ này, makefile bao gồm các hành động sau:
create_dir
: Tạo thư mụcbin
vàobj
nếu chúng không tồn tại.compile_program
: Biên dịch các file mã nguồn C++ (main.cpp
vàutils.cpp
) và liên kết chúng để tạo chương trìnhmyprogram
trong thư mụcbin
.clean
: Xóa tất cả các file đối tượng trong thư mụcobj
.
Khi chạy lệnh make
với makefile này, các hành động sẽ được thực hiện theo thứ tự định nghĩa trong makefile. Bằng cách tạo ra các thư mục và file đối tượng trước, chúng ta đảm bảo rằng chương trình sẽ được biên dịch và liên kết thành công. Nếu bạn chỉ muốn thực hiện một hoặc một số hành động, bạn có thể chỉ định tên của chúng khi chạy lệnh make
. Ví dụ: make compile_program
chỉ biên dịch và liên kết chương trình, nhưng không tạo hoặc xóa bất kỳ file hay thư mục nào.