Từ các thông tin GNU thủ
biến và chức năng trong tất cả các bộ phận của một makefile được mở rộng khi đọc, trừ trong những bí kíp, hai bên cánh tay phải của định nghĩa biến sử dụng '=', và các xác định biến số sử dụng chỉ thị 'xác định'.
Biến mục tiêu cụ thể chỉ áp dụng trong công thức nấu ăn. Trong
$(OBJS): | $(OBJDIR)
và
$(OBJDIR):
nó là nhận được biến toàn cầu.
Vì vậy, làm việc qua những gì sẽ xảy ra khi bạn chạy make Debug32
, nó sẽ xem nội dung của OBJS
là điều kiện tiên quyết, dẫn đến quy tắc đầu tiên ở trên. $(OBJDIR)
đã được thay thế bằng giá trị toàn cầu, và điều này khớp với tên mục tiêu trong quy tắc thứ hai cũng được thay thế theo cùng một cách.
Tuy nhiên, khi chúng tôi nhận được vào công thức:
echo mkdir $(OBJDIR) - [email protected]
$(OBJDIR)
chưa được thay thế, vì vậy nó được giá trị biến mục tiêu cụ thể.
Một phiên bản làm việc
.SECONDEXPANSION:
all: Debug32
# Object directory set by target
Debug32: OBJDIR = objdir32
OBJDIR = wrongdirectory
Debug32: OBJS = $(addprefix $(OBJDIR)/,obj.o)
OBJS = wrongobjs
Debug32: $$(OBJS)
echo OBJS are $(OBJS)
echo OBJDIR is $(OBJDIR)
%/obj.o: | %
touch [email protected]
OBJDIRS = objdir32 wrongdirectory anotherdirectory
$(OBJDIRS):
# mkdir $(OBJDIR)
mkdir [email protected]
Sự thay đổi chính đang sử dụng $$
trong dòng này:
Debug32: $$(OBJS)
Với duy nhất một $
, tôi nhận được thông báo lỗi
make: *** No rule to make target `wrongobjs', needed by `Debug32'. Stop.
Tuy nhiên, với số $$
, tôi nhận được
echo OBJS are objdir32/obj.o
OBJS are objdir32/obj.o
echo OBJDIR is objdir32
OBJDIR is objdir32
Việc sử dụng mở rộng phụ đã cho phép truy cập biến mục tiêu cụ thể trong điều kiện tiên quyết.
Thay đổi khác là tôi đã tạo một biến số mục tiêu cụ thể (vì đó là biến số). Để có một quy tắc để xây dựng OBJS
bất kỳ giá trị của nó, tôi đã phải sử dụng một quy tắc mẫu:
%/obj.o: | %
Để tránh việc có một dòng riêng biệt cho từng đối tượng tập tin, bạn có thể làm như sau thay vì:
OBJ_BASENAMES=obj.o obj2.o obj3.o
$(addprefix %/,$(OBJ_BASENAMES)): | %
touch [email protected] # Replace with the proper recipe
dòng chứa addprefix
nở vĩ mô để
%/obj.o %/obj2.o %/obj3.o: | %
Sau đó chạy make anotherdirectory/obj2.o
tạo một thư mục gọi là "anotherdirectory" linh sam st, và tạo ra một tập tin gọi là "obj2.o" bên trong nó.
Lưu ý rằng tất cả các thư mục có thể phải được liệt kê trong OBJDIRS
. Không có cách nào để thu thập tất cả các giá trị quy tắc cụ thể của OBJDIR, vì vậy việc liệt kê chúng là lựa chọn tốt nhất. Phương án thay thế là quy tắc % :
để xây dựng bất kỳ thư mục nào có khả năng khớp và xây dựng bất kỳ mục tiêu nào, điều này có thể gây rủi ro. (Nếu bạn từ bỏ việc sử dụng các biến mục tiêu cụ thể, có một cách khác để nhận danh sách thư mục có thể được tạo: sử dụng các biến có tên có thể dự đoán như Debug32_OBJDIR
và tạo danh sách giá trị của chúng bằng cách sử dụng chức năng.)
Ngoài ra, một nguyên tắc chung mà không cần liệt kê các file đối tượng:
SOURCE=$(basename $(notdir [email protected])).cpp
DIR=$(patsubst %/,%,$(dir [email protected]))
%.o: $$(SOURCE) | $$(DIR)
touch [email protected] # Replace with proper recipe
không có tính năng đọc một quy tắc trong bối cảnh của mỗi mục tiêu, thay thế trong các biến mục tiêu cụ thể và có được một quy tắc mới cho mỗi mục tiêu. Quy tắc chung không thể được viết theo cách này bằng cách sử dụng các biến nhắm mục tiêu cụ thể.
này hoạt động, nhưng có vẻ như tôi phải chỉ định Thư mục đối tượng hai lần và mỗi tệp .o hai lần, bao gồm quy tắc mẫu cho mỗi tệp nguồn.Tôi đang đi về điều này tất cả sai? Có vẻ như quá khó để tạo một makefile chung đơn giản cho hai hoặc nhiều mục tiêu. – Jeff
Tôi đã thêm một cách để bao gồm tất cả các tệp đối tượng. Tôi hy vọng nó có thể mà không liệt kê tất cả (một cái gì đó như '% .o: $$ (basename%). Cpp | $$ (dir $$ @)') nhưng tôi đã không có nó để làm việc được nêu ra. –
Tôi đã thêm một phiên bản và ghi chú dễ sử dụng hơn để liệt kê các thư mục. Phương pháp xây dựng thư mục của Mark Galeck có vẻ như nó có thể tốt hơn. –