2012-06-18 26 views
5

Tôi muốn sử dụng $(error ...) để hủy bỏ quy trình thực hiện của mình nếu các điều kiện tiên quyết nhất định không được đáp ứng. Mục tiêu fails_to_work sẽ bị hủy khi không thành công test -d /foobar.

BAD.mk

all: this_works fails_to_work 

this_works: 
     @echo echo works... 
     @test -d ~ || echo ~ is not a directory 
     @test -d /foobar || echo /foobar is not a directory 

fails_to_work: 
     @echo error does not work... 
     @test -d ~ || $(error ~ is not a directory) 
     @test -d /foobar || $(error /foobar is not a directory) 

$ make -f BAD.mk

echo works... 
/foobar is not a directory 
BAD.mk:9: *** ~ is not a directory. Stop. 

Như bạn thấy, thậm chí không "lỗi không hoạt động ..." được lặp lại vào màn hình. Công thức cho fails_to_work không thành công trước khi bắt đầu. Tôi giải quyết điều này như thế nào? Một trong các trường hợp sử dụng của tôi là @test -d $(MY_ENV_VAR), nhưng tôi không nghĩ rằng khác với các đường dẫn mã hóa cứng được đưa ra trong ví dụ.

CẬP NHẬT (phiên bản thông tin)

$ make --version

GNU Make 3.81 
Copyright (C) 2006 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. 
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A 
PARTICULAR PURPOSE. 

This program built for x86_64-pc-linux-gnu 

Trả lời

5

Bạn đang cố gắng để có được những thứ vỏ trong một công thức có điều kiện gọi thứ makefile, mà không làm việc , như bạn đã tìm thấy.

tôi có thể nghĩ ra hai lựa chọn:

  1. Đơn giản chỉ cần loại bỏ những thứ $(error). Nếu test không thành công, thì nó sẽ trả về trạng thái thoát khác 0 và quá trình Thực hiện sẽ chấm dứt tại thời điểm đó.

  2. Hãy kiểm tra ra khỏi sự cai trị, và sử dụng một Make có điều kiện (do đó gọi chức năng vỏ), ví dụ:

    ifeq ($(shell test -d /foobar; echo $$?),1) 
    $(error Not a directory) 
    endif 
    
+0

Cảm ơn. Đề nghị đầu tiên của bạn hoạt động (mà tôi đang áp dụng như vậy: 'if! Test -d/foobar; sau đó echo"/foobar không phải là một thư mục "; thoát 1; fi'), nhưng thứ hai của bạn thì không. Với một thư mục hợp lệ, lỗi vẫn được nhấn. –

0

Tại sao bạn không chỉ cần sử dụng lệnh shell exit 1 thay của $(error ...)? Có lý do gì để sử dụng sau này không?

try_this: 
    @test -d /foobar || { echo /foobar is not a directory; exit 1; } 

or_this: 
    @if [ ! -d /foobar ]; then echo /foobar is not a directory; exit 1; fi 

Cả hai điều này sẽ hủy bỏ quá trình thực hiện trừ khi -k flag được chỉ định.

-k --keep-going

Tiếp tục càng nhiều càng tốt sau khi một lỗi. Trong khi mục tiêu thất bại, và những mục tiêu phụ thuộc vào nó, không thể được làm lại, các điều kiện tiên quyết khác của các mục tiêu này có thể được xử lý tất cả như nhau.

+0

Tôi đã chụp cho cửa sổ cmd shell/sh portability theo niềm tin sai lầm rằng 'test -d' đã có sẵn trong cả hai. Tuy nhiên, tôi vẫn quan tâm đến cách chính xác để điều kiện gọi $ (lỗi ...). –

5

Lệnh vỏ cho công thức làm được lưu trữ hiệu quả dưới dạng một biến mở rộng đệ quy. Tại thời điểm quyết định chạy công thức, nó mở rộng biến, và sau đó chạy mỗi dòng trong lời gọi shell của chính nó. Bất kỳ$(error ...) nào được mở rộng sẽ làm cho việc hủy bỏ ngay cả trước khi gọi lệnh đầu tiên.

Lưu ý rằng chi nhánh chưa được khai báo của $(if ...) hoặc $(or ...) & c. sẽ không được mở rộng.Vì vậy, bạn có thể làm

.PHONY: rule-with-assert 
rule-with-assert: 
    $(if $(realpath ${should-be-file}/),$(error Assertion failure: ${should-be-file} is a folder!)) 
    ⋮ 

Lưu ý rằng trailing / trong realpath.

Tất nhiên, các macro giúp dọn dẹp rất nhiều.

assert-is-file = $(if $(realpath $1/),$(error Assertion failure: [$1] is a folder!)) 

.PHONY: rule-with-assert 
rule-with-assert: 
    $(call assert-is-file,${should-be-file}) 
    ⋮ 

Cần lưu ý một lần nữa rằng việc bạn đặt $(call assert-is-file,…) vào công thức là không quan trọng. Bất kỳ $(error) sẽ được tạo khi công thức được mở rộng, trước mọi lệnh shell được chạy.

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