Hiểu cú pháp Makefile: Các vấn đề thường gặp và giải pháp (Bao gồm 'Thiếu toán tử' và 'Không tìm thấy điểm vào')

Hieu Cu Phap Makefile Cac Van De Thuong Gap Va Giai Phap Bao Gom Thieu Toan Tu Va Khong Tim Thay Diem Vao



Giống như một tệp mã chứa một hoặc nhiều dòng mã làm nội dung để làm cho nó có giá trị, tệp makefile cơ bản được xây dựng bằng cách sử dụng các biến, quy tắc và mục tiêu. Ngoài ra, còn có những yếu tố khác cần thiết để tạo một tệp thực hiện hoàn chỉnh mà không gặp bất kỳ vấn đề nào. Trong hướng dẫn này, chúng tôi sẽ thảo luận về cú pháp makefile cơ bản và các vấn đề thường gặp khi viết makefile và cung cấp giải pháp để giải quyết những vấn đề đó.

Tìm hiểu cú pháp cơ bản của Makefile

Để bắt đầu tạo một makefile, chúng tôi giải thích các thuộc tính cơ bản của một makefile thông qua ví dụ về mã makefile. Cần phải bao gồm các thuộc tính cú pháp sau trong nội dung makefile để có được tệp thực thi:







Biến đổi s: Một đối tượng lưu trữ dữ liệu cơ bản cần được sử dụng trong makefile. Các biến này được sử dụng để chỉ định trình biên dịch, cờ, tệp nguồn, tệp đối tượng và tệp đích. Trong tệp makefile mẫu sau, có tổng cộng năm biến là CXX (để đặt trình biên dịch C++), CXXFLAGSc (cờ trình biên dịch), TARGET (để đặt tên tệp thực thi đích), SRCS (để đặt tệp mã nguồn) , OBJS (để chứa các tệp đối tượng được tạo thông qua tệp mã nguồn).



Mục tiêu: Kết quả đầu ra dự kiến ​​được xây dựng từ nguồn. Nó có thể là một tệp mục tiêu hoặc bất kỳ tên tượng trưng nào: “tất cả” là mục tiêu mặc định nên được xây dựng thông qua biến “TARGET”, “$TARGET” phụ thuộc vào các biến “OBJS”, và mục tiêu “sạch” sẽ loại bỏ mục tiêu và tập tin đối tượng từ thư mục làm việc.



Quy tắc và lệnh xây dựng: Tập hợp các hướng dẫn cơ bản sẽ được thực thi để tạo mục tiêu từ tệp nguồn hoặc các phần phụ thuộc. Ví dụ: quy tắc “%.o: %.cpp” hiển thị rằng tệp có phần mở rộng “cpp” được sử dụng để tạo tệp đối tượng có phần mở rộng “o” trong khi cả hai tệp đều chứa cùng một tên. Mặt khác, lệnh xây dựng $(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS) được sử dụng để liên kết một tệp đối tượng và một tệp mục tiêu mới với nhau. Tương tự như vậy, lệnh xây dựng $(CXX) $(CXXFLAGS) -c $< -o $@ biên dịch tệp nguồn thành tệp đối tượng.





Phụ thuộc: Các phần phụ thuộc luôn ở đó khi bạn muốn tạo một tệp thực hiện. Ví dụ: mục tiêu “tất cả” phụ thuộc vào biến “TARGET” trong khi “TARGET” phụ thuộc vào biến “OBJS”. Đồng thời, biến “OBJS” phụ thuộc vào tệp nguồn thông qua biến “SRCS”.

Bình luận: Các hướng dẫn dễ hiểu của con người thường được sử dụng để giải thích mục đích của dòng mã trong trường hợp bạn sử dụng một tệp sau một thời gian dài. Trong tệp tạo tệp sau đây, chúng tôi sử dụng các nhận xét bắt đầu bằng dấu “#” để giải thích từng dòng.



CXX = g++
CXXFLAGS = -std =c++ mười một -Tường
MỤC TIÊU = Mới
SRCS = main.cpp
OBJS = $ ( SRCS:.cpp=.o )
tất cả: $ ( MỤC TIÊU )
$ ( MỤC TIÊU ) : $ ( OBJS )
$ ( CXX ) $ ( CXXCỜ ) -O $ ( MỤC TIÊU ) $ ( OBJS )
% .O: % .cpp
$ ( CXX ) $ ( CXXCỜ ) -c $ < -O $ @
lau dọn:
rm -f $ ( MỤC TIÊU ) $ ( OBJS )

Các vấn đề và giải pháp chung

Trong khi viết bất kỳ tệp makefile nào, cần phải xem xét từng chi tiết nhỏ để cuối cùng có được kết quả mong muốn. Một số vấn đề phổ biến mà người dùng thường gặp phải khi tạo tệp thực hiện. Trong phần này, chúng tôi sẽ thảo luận về những vấn đề đó và đề xuất các giải pháp khả thi như sau:

1: Không sử dụng biến

Việc sử dụng các biến trong tệp tạo tệp là điều bắt buộc vì nó bắt buộc phải có để thiết lập trình biên dịch, tệp đích, tệp nguồn, v.v. Vấn đề phổ biến nhất có thể gặp phải là không sử dụng bất kỳ biến nào trong tệp tạo tệp. Do đó, hãy đảm bảo sử dụng các biến thiết yếu như CXX, CXXFLAGSc(cờ trình biên dịch), TARGET, SRCS và OBJS trong tệp tạo tệp mẫu trước đó.

2: Thiếu dấu phân cách

Trong khi viết một makefile, cần phải xem xét kỹ các quy tắc thụt lề vì việc sử dụng dấu cách thay vì tab sẽ dẫn bạn đến vấn đề “thiếu dấu phân cách” trong khi thực hiện lệnh “make”. Ví dụ: chúng tôi thêm khoảng trắng ở đầu quy tắc ở dòng 13 và xóa tab.

$ ( MỤC TIÊU ) : $ ( OBJS )
$ ( CXX ) $ ( CXXCỜ ) -O $ ( MỤC TIÊU ) $ ( OBJS )

Khi thực hiện truy vấn 'make', chúng tôi gặp lỗi 'thiếu dấu phân cách' ở dòng 13 và tệp ngừng chạy. Để tránh vấn đề này, hãy đảm bảo sử dụng “tab” thay vì dấu cách.

làm

Để tránh sự cố này, hãy đảm bảo sử dụng “tab” thay vì dấu cách như mô tả trong hình ảnh sau:

$ ( MỤC TIÊU ) : $ ( OBJS )
$ ( CXX ) $ ( CXXCỜ ) -O $ ( MỤC TIÊU ) $ ( OBJS )

3: Vấn đề “Không tìm thấy điểm vào”

Lỗi này đa phần xảy ra do file nguồn chứ không phải do makefile như khi bạn lỡ sử dụng hàm “main()” trong file mã nguồn. Ví dụ: chúng tôi thay thế định nghĩa hàm main() bằng một khai báo hàm đơn giản do người dùng định nghĩa.

#include
chương trình int ( ) {
char v;
std::cout << 'Nhập một giá trị:' ;
std::cin >> TRONG;
std::cout << TRONG << std::endl;
trở lại 0 ;
}

Khi thực hiện lệnh “make” trên dấu nhắc lệnh của Windows, chúng tôi gặp phải “tham chiếu không xác định đến ‘WinMain’”. Điều này là do trình biên dịch không tìm thấy bất kỳ điểm vào nào để bắt đầu thực thi tệp C++. Để giải quyết vấn đề này, hãy thay thế “show” bằng “main”.

4: Sử dụng tiện ích mở rộng không chính xác

Đôi khi, người dùng có thể vô tình sử dụng sai phần mở rộng của tệp nguồn được sử dụng trong tệp thực hiện. Sử dụng sai tiện ích mở rộng sẽ dẫn đến lỗi thời gian chạy, tức là không có quy tắc nào để tạo mục tiêu. Chúng tôi tạo một tệp thực hiện để xây dựng tệp thực thi và tệp đối tượng cho tệp C++. Ở dòng thứ bảy, chúng tôi cung cấp tệp nguồn có phần mở rộng “c”.

CXX := g++
CXXFLAGS := -std =c++ mười một -Tường
MỤC TIÊU = mới
SRCS = main.c
OBJS = $ ( SRCS:.cpp=.o )
Tất cả: $ ( MỤC TIÊU )
$ ( MỤC TIÊU ) : $ ( OBJS )

Việc chạy lệnh “make” sẽ dẫn chúng ta đến lỗi “Không có quy tắc nào để tạo mục tiêu ‘main.c’”. Để tránh sự cố này, hãy đảm bảo sử dụng đúng phần mở rộng tệp nguồn.

làm

5: Thiếu phụ thuộc

Trong khi viết tệp tạo tệp, bạn nên bao gồm tất cả các phần phụ thuộc cho tệp nguồn để có được kết quả mong muốn. Ví dụ: tệp mã C++ của chúng tôi sử dụng tệp “myheader.h” làm phụ thuộc. Vì vậy, chúng tôi đề cập đến nó trong tệp mã C++ như sau:

#include
#include “myheader.h”
chương trình int ( ) {
char v;
std::cout << 'Nhập một giá trị:' ;
std::cin >> TRONG;
std::cout << TRONG << std::endl;
trở lại 0 ;
}

Trong tệp thực hiện, chúng tôi cố tình bỏ qua việc sử dụng tệp “myheader.h” trong quy tắc xây dựng được viết ở dòng 9.

% .O: % .cpp
$ ( CXX ) $ ( CXXCỜ ) -c $ < -O $ @

Bây giờ, trong khi sử dụng lệnh “make”, chúng ta gặp phải lỗi “Không cần làm gì cho ‘tất cả’”.

làm

% .O: % .cpp myheader.h
$ ( CXX ) $ ( CXXCỜ ) -c $ < -O $ @

Để tránh sự cố đã nói và chạy mã nguồn thành công, hãy đề cập đến tên tệp “myheader.h” ở dòng thứ chín của tệp thực hiện như được mô tả trong phần sau:

Phần kết luận

Trong hướng dẫn này, chúng tôi đã giải thích kỹ lưỡng cú pháp của makefile bằng cách sử dụng các nội dung cần thiết như biến, lệnh xây dựng, quy tắc, v.v. Ví dụ về mã được đưa vào để xây dựng cú pháp rõ ràng hơn. Cuối cùng, chúng tôi đã thảo luận về một số vấn đề thường gặp và giải pháp của chúng mà người dùng có thể gặp phải khi tạo tệp thực hiện.