2009-06-10 50 views
8

Tôi thấy tôi đang viết rất nhiều Makefiles có thể được dọn sạch với việc sử dụng các danh sách tự động n. Nhưng tôi không thể tìm thấy bất kỳ cách nào để làm điều này đúng (và sạch). Cho đến nay tôi chỉ có thể tìm ra bằng cách sử dụng $ (vỏ ...)tr, sed hoặc các tiêu chuẩn khác không phải Makefile.Lặp lại các danh sách trong Makefiles?

Ví dụ, tôi muốn làm điều này:

XYZs = \ 
    dog.c pull_tail bark \ 
    duck.c chase  quack \ 
    cow.c tip  moo 

all: 
    @- $(foreach X Y Z,$(XYZs), \ 
     $(CC) $X -o bully/$Y ; \ 
     ln bully/$Y sounds/$Z ; \ 
    ) 

Có cách nào tốt để lặp n danh sách -tuple trong Makefiles? Cảm ơn!

Trả lời

10

Makefiles cơ bản là khai báo trong tự nhiên, vì vậy tôi không nghĩ rằng làm cho chính nó cung cấp những gì bạn muốn. Tuy nhiên, bạn dường như muốn kết hợp một số giá trị chuỗi với các mục tiêu cụ thể, vì vậy có thể tính năng Target specific variable values của GNU sẽ được quan tâm. Đây là một chiết xuất từ ​​hướng dẫn:

Có thêm một tính năng đặc biệt của biến mục tiêu cụ thể: khi bạn định nghĩa một biến mục tiêu cụ thể, rằng giá trị biến cũng có hiệu lực cho tất cả phụ thuộc của mục tiêu này (trừ khi những phụ thuộc đó ghi đè nó với giá trị biến số cụ thể của mục tiêu riêng là ). Vì vậy, ví dụ, một tuyên bố như thế này:

prog : CFLAGS = -g

prog : prog.o foo.o bar.o

sẽ thiết lập CFLAGS--g trong lệnh kịch bản cho prog, nhưng nó cũng sẽ thiết CFLAGS--g trong lệnh tập lệnh tạo prog.o, foo.o, và bar.o và bất kỳ tập lệnh nào tạo phụ thuộc của chúng.

Nếu bạn chưa đọc nó, GNU làm thủ công khá là tốt.

Edit: Để làm những gì bạn hỏi về trong bình luận của bạn:

dog: ANIMAL=dog.c BULLY=pull_tail SOUND=bark 

sử dụng:

dog: ANIMAL=dog.c 
dog: BULLY=pull_tail 
dog: SOUND=bark 
+0

Tuyệt vời và có thể là một nửa ở đó! Có cú pháp để làm điều này? chó: ANIMAL = dog.c BULLY = pull_tail SOUND = bark – Dylan

+0

+1, rất đẹp. –

+2

Vấn đề không phải là thực hiện là khai báo, nó là nó không cung cấp một cú pháp khai báo cho mô hình này thường xuyên cần thiết! – reinierpost

0

Bạn đang làm ngược.

Bạn đang cố gắng đối xử với bạn như một kịch bản. Nó không phải, thay vào đó là một bộ quy tắc về cách tạo ra X cho Y. Sau đó, công cụ tạo ra con số ra những gì cần phải xảy ra để có được kết quả đó.

Ví dụ được đưa ra, bạn thực sự nên sử dụng tập lệnh cho các bước tạo. Có lẽ gọi đó là từ thực hiện, nhưng hãy để làm cho xử lý các công cụ CC.

+4

Đây là một hạn chế trong thực hiện mà không có lý do để có được ở nơi đầu tiên, và có thể được làm việc xung quanh với $ (foreach) anyway. – reinierpost

2

Không có điều gì tôi biết, nhưng đó là bởi vì bạn đang cố gắng bắt buộc làm việc ans một ngôn ngữ bắt buộc, khi đó không phải là nó là gì.

Trong GNU làm cho bạn có thể muốn làm điều gì đó như:

pull_tail : SOUND=bark 
pull_tail : dog.c 
     $(CC) $< -o $^ 
     ln [email protected] $(SOUND) 

chase : SOUND=quack 
chase : duck.c 
     $(CC) $< -o $^ 
     ln [email protected] $(SOUND) 

... 

Hoặc tốt hơn, xác định lại quy tắc mặc định cho các file .c để xử lý các liên kết cho bạn, nhưng cấu trúc kỳ lạ của tên của bạn (tên chương trình không có mối quan hệ từ vựng với tên nguồn) làm cho điều đó trở nên khó khăn.

Nếu những gì bạn muốn để có thể xây dựng lại này một cách nhanh chóng mà không có một rất nhiều chỉnh sửa mặt, có thể bạn muốn viết một kịch bản để tạo lại framgment makefile từ dữ liệu và sử dụng các tính năng include của GNU làm ...

5

Tôi muốn kiểm tra hướng dẫn sử dụng GNU trên foreach. đây là một số snips ngẫu nhiên mà tôi đã sử dụng trong một dự án khác ... ví dụ là không đầy đủ, nhưng có lẽ nó sẽ cho bạn một số ý tưởng? Tôi có thể làm sạch này lên sau này nếu tôi đã có nhiều thời gian hơn ...

REMAKE_PROGS:= dog duck cow 

XYZs = \ 
    dog.c pull_tail bark \ 
    duck.c chase  quack \ 
    cow.c tip  moo 

$(foreach src, $(XYZs), $(eval $MAKE $(src)) 

$(REMAKE_PROGS): 
     @echo "\n# === [email protected] linking\n" 
     $(call compile,[email protected],$([email protected]),$(CXX),$(MPICXX),$(LDFLAGS) $(LIBS) $(SYSLIBS) $(OTHER_LIB) $(EXTRA_LD_FLAGS)) 
     @echo "\n# --- [email protected] compiled\n" 

define compile 
    @mkdir -p $(dir $(1)) 
    $(if ${ANNOUNCE},@echo "\n# +++ ${MAKECMDGOALS} compiling\n" $(eval ANNOUNCE=)) 
    $(call compiler,$(1),NOMPI,$(3),$(4)) 
    $(eval MY_FLAGS=$(FLAGS_$(1)) $(5)) 
    $(if $(filter %xlf %xlf90,$(COMPILER_$(1))),$(eval MY_FLAGS:=$(MY_FLAGS:-D%=-WF,-D%))) 
    $(strip $(COMPILER_$(1)) $(2) $(MY_FLAGS) -o $(1)) 
endef 
+0

Tôi đang sử dụng không foreach-gọi-thực hiện, nhưng foreach-eval-gọi, mà chỉ là xấu xí. Xem http://www.gnu.org/software/automake/manual/make/Eval-Function.html#Eval-Function – reinierpost

0

Bạn có thể sử dụng quy tắc mặc định cho một bộ các tập tin với phần mở rộng tương tự như trong để biên dịch mỗi file c một o. Tất nhiên bạn không bị giới hạn ở bất kỳ phần mở rộng tập tin đặc biệt nào. Để biên dịch một bộ .c tập tin mà bạn có thể làm điều đó như thế này:

OBJS = foo.o bar.o baz.o 
OUT = myprog 

all: $(OBJS) 
     $(SILENT) echo "LD [email protected]" 
     $(SILENT) $(CPP) -o $(OUT) $^ $(LDFLAGS) 

%.o: %.c 
     $(SILENT) echo "CC $<" 
     $(SILENT) $(CC) $(CCOPTS) -o [email protected] -c $< 
+0

Sự cố bắt đầu khi bạn cần sử dụng một "giá trị hiện tại $ (OBJ)" trong quy tắc mẫu. GNU make không cung cấp cú pháp khai báo cho điều đó, và $ (foreach) là một giải pháp xấu (nhưng hoàn toàn chức năng). – reinierpost

6

Cảm ơn đã gợi ý - sau khi một số hack Tôi nghĩ rằng đây là hơn những gì tôi đã hy vọng cho:

XYZs = \ 
    dog.c:pull_tail:bark \ 
    duck.c:chase:quack \ 
    cow.c:tip:moo 

all: 
    @- $(foreach XYZ,$(XYZs), \ 
     $(eval X = $(word 1,$(subst :, ,$(XYZ)))) \ 
     $(eval Y = $(word 2,$(subst :, ,$(XYZ)))) \ 
     $(eval Z = $(word 3,$(subst :, ,$(XYZ)))) \ 
     \ 
     $(CC) $X -o bully/$Y ; \ 
     ln bully/$Y sounds/$Z ; \ 
    ) 

Can ai làm tốt hơn?

Các vấn đề liên quan