2014-08-31 13 views
8

Dưới đây là một ví dụ từ GNU Make manual section on Secondary Expansion (hơi đơn giản):

foo_SRCS := bar.c baz.c 

.SECONDEXPANSION: 
# [email protected] expands to the target ("foo" in this case) 
foo: $$(patsubst %.c,%.o,$$([email protected]_SRCS)) 

này hoạt động tuyệt vời; nó được xây dựng bar.obaz.o:

cc -c -o bar.o bar.c 
cc -c -o baz.o baz.c 

Nhưng nếu tôi tinh chỉnh ví dụ này chỉ hơi, các patsubst dừng làm việc:

all: foo.a 

foo_SRCS := bar.c baz.c 

.SECONDEXPANSION: 
# $$* expands to the stem of the match ("foo" in this case). 
%.a: $$(patsubst %.c,%.o,$$($$*_SRCS)) 
     ar rcs [email protected] $^ 

Nó không còn xây dựng bar.obaz.o, và thay vào đó là sử dụng *.c file trực tiếp như điều kiện tiên quyết!

ar rcs foo.a bar.c baz.c 

Xin lưu ý rằng phần $$($$*_SRCS) đang làm việc rõ ràng, bằng chứng thực tế là nó tìm thấy foo_SRCS và sử dụng mà là điều kiện tiên quyết. Nhưng vì lý do nào đó, phần patsubst đã trở thành no-op! Thay vì thay thế %.c bằng %.o, chỉ cần sử dụng trực tiếp foo_SRCS.

Điều gì đang xảy ra ở đây? Làm thế nào tôi có thể có được ví dụ của tôi để làm việc?

EDIT: Tôi đã có một giả thuyết cho rằng % ký tự bên trong patsubst đã bị đánh giá sớm, bằng cách sử dụng phù hợp với gốc (foo), do đó patsubst bản thân đang tìm kiếm một cái gì đó như thế này:

$(patsubst foo.c,foo.o,bar.c baz.c) 

Để kiểm tra lý thuyết này, tôi đã thêm một tập tin gọi foo.c để foo_SRCS:

all: foo.a 

foo_SRCS := foo.c bar.c baz.c 

.SECONDEXPANSION: 
# $$* expands to the stem of the match ("foo" in this case). 
%.a: $$(patsubst %.c,%.o,$$($$*_SRCS)) 
     ar rcs [email protected] $^ 

Đó dẫn đến một cái gì đó thậm chí lạ:

make: *** No rule to make target `foo.a', needed by `all'. Stop. 

Trả lời

4

Ký tự phần trăm đang được đọc bằng cách đặt làm khớp với ký tự đại diện trong thân cây và đang được thay thế bằng khớp gốc. Nếu bạn đánh dấu vào make -p đầu ra ví dụ của bạn, bạn sẽ thấy rằng dòng mục tiêu phân tích cú pháp như sau:

%.a: $(patsubst %.c,%.o,$($*_SRCS)) 

nào, càng xa càng làm cho là có liên quan, chỉ là một bộ thực sự kỳ lạ của mục tiêu theo khuôn mẫu (hoặc một cái gì đó như thế).

Nếu bạn thoát khỏi nhân vật phần trăm từ làm cho phân tích cú pháp theo một cách tương tự như cách bạn thoát khỏi $ từ thực hiện đánh giá, bạn có thể có được những gì bạn muốn làm việc:

pc := % 
$$(patsubst $$(pc).c,$$(pc).o,$$($$*_SRCS)) 

Để biết thông tin thêm substitution references (tức $(foo_SRCS:.c=.o)) có thể được sử dụng cho các phép biến đổi như thế này thay cho lệnh gọi hàm patsubst dài hơn. Tuy nhiên, trong trường hợp này, khi nó hoạt động trong trường hợp này với sự thoát tương tự của : (qua c := :), nó dường như không hoạt động như điều kiện tiên quyết duy nhất của mục tiêu (với việc đưa ra lỗi Makefile:23: *** commands commence before first target. Stop. mà tôi không hiểu rõ) ít nhất với GNU Hãy 3.81.

+0

Cảm ơn! Tôi không chắc mình hiểu 100% những gì đang diễn ra, nhưng tôi có thể xác nhận rằng công việc sửa chữa của bạn. –

+0

Trình phân tích cú pháp của Make không phải là rất thông minh. Khi thực hiện thấy nỗ lực của bạn nó unescapes '$$' vào '$' và kết thúc với dòng được chỉ ra ở trên. Sau đó nó thấy rằng như là một quy luật mẫu bình thường. Các quy tắc mẫu lấy mẫu đích, khớp với tên tệp đích đối với nó để trích xuất một gốc và sau đó thay thế gốc đó trong danh sách điều kiện tiên quyết thay cho mỗi '%'. Điều này phá vỡ patsubst vì nó không còn chứa bất kỳ ký tự '%' nào khi mở rộng thứ cấp mở rộng nó. Việc thoát các ký tự '%' cho phép chỉ xem chúng khi mở rộng thứ cấp đang diễn ra chứ không phải khi quy tắc mẫu được kết hợp với gốc. –

+0

Tất cả những điều đó hợp lý với tôi. Phần tôi không hiểu sau đó là lý do tại sao ví dụ ban đầu (từ Make manual) làm việc ở tất cả. Tại sao nó sẽ không thất bại trong cùng một cách? –

4

Bạn đang trộn ba tính năng không hoạt động tốt với nhau: secondary expansion, pattern rulespatsubst. Tôi sẽ cố gắng giải thích chi tiết những gì thực hiện đang làm khi đánh giá mã của bạn (AFAIUI).

Hãy bắt đầu với Makefile đầu tiên của bạn:

foo_SRCS := bar.c baz.c 

.SECONDEXPANSION: 
%.a: $$(patsubst %.c,%.o,$$($$*_SRCS)) 
     ar rcs [email protected] $^ 

đọc giai đoạn. Tất cả các dấu hiệu đồng đô la được thoát, vì vậy không có đánh giá nào xảy ra ở đây. Thực hiện nhập quy tắc sau trong cơ sở dữ liệu của nó:

%.a: $(patsubst %.c,%.o,$($*_SRCS)) 

Thay thế mẫu. Theo như thực hiện có liên quan, đây chỉ là một quy tắc mẫu khác, với mục tiêu %.a và hai điều kiện tiên quyết được phân cách bằng khoảng trắng: $(patsubst%.c,%.o,$($*_SRCS)).

foo.a phù hợp với mô hình mục tiêu, và vì vậy đầu tiên% trong từng điều kiện tiên quyết sẽ được thay thế bởi foo. Quy tắc trở thành:

foo.a: $(patsubst foo.c,%.o,$($*_SRCS)) 

Mục cập nhật giai đoạn. Như bạn đã yêu cầu mở rộng thứ cấp, mô hình được đánh giá một lần nữa trong giai đoạn cập nhật mục tiêu:

foo.a: $(patsubst foo.c,%.o,$($*_SRCS)) 
==> foo.a: $(patsubst foo.c,%.o,bar.c baz.c) 
==> foo.a: bar.c baz.c 

Và do đó hãy kết thúc thực hiện lệnh

ar rcs foo.a bar.c baz.c 

Và những gì về foo.c? Nếu bạn thêm foo.c để foo_SRCS, việc mở rộng thứ trông như thế này:

foo.a: $(patsubst foo.c,%.o,$($*_SRCS)) 
==> foo.a: $(patsubst foo.c,%.o,foo.c bar.c baz.c) 
==> foo.a: %.o bar.c baz.c 

Và sự cai trị không thành công vì làm cho không biết làm thế nào để xây dựng %.o.

Làm việc xung quanh. Bạn có thể thoát khỏi các ký tự % bằng dấu gạch chéo ngược:

.SECONDEXPANSION: 
%.a: $(patsubst \%.c,\%.o,$$($$*_SRCS)) 
     ar rcs [email protected] $^ 
Các vấn đề liên quan