2011-01-18 42 views
84

Trong một Makefile, một công thức deploy cần một biến môi trường ENV được thiết lập để thực hiện đúng bản thân, trong khi những người khác không quan tâm, ví dụ:biến Makefile là điều kiện tiên quyết

ENV = 

.PHONY: deploy hello 

deploy: 
    rsync . $(ENV).example.com:/var/www/myapp/ 

hello: 
    echo "I don't care about ENV, just saying hello!" 

Làm thế nào tôi có thể chắc chắn rằng biến này được đặt, ví dụ: có cách nào để khai báo biến makefile này là điều kiện tiên quyết của công thức triển khai, như:

deploy: make-sure-ENV-variable-is-set 

?

Cảm ơn bạn.

+0

Ý của bạn là gì, "hãy đảm bảo biến này được đặt"? Bạn có nghĩa là xác minh hoặc đảm bảo? Nếu nó không được thiết lập trước đây, nên 'make' đặt nó, hoặc đưa ra một cảnh báo, hoặc tạo ra một lỗi nghiêm trọng? – Beta

+1

Biến này phải được chỉ định bởi chính người dùng - vì anh ta là người duy nhất biết môi trường của mình (dev, prod ...) - ví dụ bằng cách gọi 'make ENV = dev' nhưng nếu anh ta quên' ENV = dev Công thức ',' deploy' sẽ thất bại ... – abernier

Trả lời

108

này sẽ gây ra một lỗi nghiêm trọng nếu ENV là undefined và một cái gì đó cần nó (trong GNUMake, anyway).

.PHONY: deploy check-env 

deploy: check-env 
    ... 

other-thing-that-needs-env: check-env 
    ... 

check-env: 
ifndef ENV 
    $(error ENV is undefined) 
endif 

(Lưu ý rằng ifndef và endif không thụt vào, "$ (lỗi" được thụt vào với không gian, không phải là một tab -. they control what make "sees", taking effect before the Makefile is run)

+5

Tôi nhận được 'ENV không xác định' khi chạy tác vụ ** không ** có kiểm tra-env làm điều kiện tiên quyết. – raine

+0

@rane: Thật thú vị. Bạn có thể đưa ra một ví dụ hoàn chỉnh tối thiểu không? – Beta

+0

Ở đây, https://gist.github.com/raneksi/5579022 – raine

2

Bạn có thể sử dụng ifdef thay vì mục tiêu khác.

.PHONY: deploy 
deploy: 
    ifdef ENV 
     rsync . $(ENV).example.com:/var/www/myapp/ 
    else 
     @echo 1>&2 "ENV must be set" 
     false       # Cause deploy to fail 
    endif 
+0

Hey, thx cho câu trả lời của bạn nhưng không thể chấp nhận nó vì mã trùng lặp mà gợi ý của bạn tạo ra ... tất cả 'triển khai' hơn không phải là công thức duy nhất phải kiểm tra Biến trạng thái 'ENV'. – abernier

+0

sau đó chỉ cần cấu trúc lại. Sử dụng câu lệnh '.PHONY: deploy' và' deploy: 'trước khối ifdef và loại bỏ sự trùng lặp. (btw Tôi đã chỉnh sửa câu trả lời để phản ánh đúng phương pháp) –

5

Như tôi đã nhìn thấy các lệnh riêng của mình cần biến ENV để bạn có thể kiểm tra xem nó trong lệnh bản thân:

.PHONY: deploy check-env 

deploy: check-env 
    rsync . $(ENV).example.com:/var/www/myapp/ 

check-env: 
    if test "$(ENV)" = "" ; then \ 
     echo "ENV not set"; \ 
     exit 1; \ 
    fi 
+0

Vấn đề với điều này là 'deploy' không nhất thiết là công thức duy nhất cần biến này. Với giải pháp này, tôi phải kiểm tra trạng thái 'ENV' cho từng cái một ... trong khi tôi muốn giải quyết nó như là một điều kiện tiên quyết (loại) duy nhất. – abernier

+0

@abernier Đã cập nhật câu trả lời – ssmir

56

Bạn có thể tạo một mục tiêu bảo vệ ngầm, để kiểm tra rằng biến trong thân cây được định nghĩa như sau:

guard-%: 
    @ if [ "${${*}}" = "" ]; then \ 
     echo "Environment variable $* not set"; \ 
     exit 1; \ 
    fi 

sau đó bạn thêm một mục tiêu bảo vệ-ENVVAR bất cứ nơi nào bạn muốn khẳng định rằng một biến được định nghĩa như sau:

change-hostname: guard-HOSTNAME 
     ./changeHostname.sh ${HOSTNAME} 

Nếu bạn gọi 'thực hiện thay đổi tên máy chủ', mà không thêm HOSTNAME = somehostname trong cuộc gọi, bạn sẽ gặp lỗi và quá trình tạo sẽ không thành công.

+3

Đó là giải pháp thông minh, tôi thích nó :) –

+0

Tôi biết rằng đây là một câu trả lời cổ, nhưng có lẽ ai đó vẫn đang xem nó nếu không tôi có thể đăng lại câu hỏi này như một câu hỏi mới ... Tôi đang cố gắng thực hiện mục tiêu tiềm ẩn này "bảo vệ" để kiểm tra các biến môi trường được thiết lập và nó hoạt động theo nguyên tắc, tuy nhiên các lệnh trong quy tắc "guard-%" thực sự được in ra trình bao. Điều này tôi muốn ngăn chặn. Sao có thể như thế được? – genomicsio

+2

OK. tìm thấy các giải pháp bản thân mình ... @ ở đầu của dòng lệnh quy tắc là bạn của tôi ... – genomicsio

3

Một vấn đề có thể xảy ra với các câu trả lời đã cho cho đến thời điểm đó là thứ tự phụ thuộc trong thực hiện không được xác định. Ví dụ: chạy:

make -j target 

khi target có một vài phụ thuộc không đảm bảo rằng những thứ này sẽ chạy theo bất kỳ thứ tự cụ thể nào.

Giải pháp cho việc này (để đảm bảo rằng ENV sẽ được kiểm tra trước khi công thức nấu ăn được lựa chọn) là để kiểm tra ENV trong đầu tiên vượt qua làm của, bên ngoài của bất kỳ công thức:

## Are any of the user's goals dependent on ENV? 
ifneq ($(filter deploy other-thing-that-needs-ENV,$(MAKECMDGOALS)),$()) 
ifndef ENV 
$(error ENV not defined) 
endif 
endif 

.PHONY: deploy 

deploy: foo bar 
    ... 

other-thing-that-needs-ENV: bar baz bono 
    ... 

Bạn có thể đọc về các chức năng khác nhau/biến được sử dụng here$() chỉ là một cách để tuyên bố rõ ràng rằng chúng tôi đang so sánh với "không có gì".

20

Inline biến

Trong makefiles của tôi, tôi thường sử dụng một biểu thức như:

deploy: 
    test -n "$(ENV)" # $$ENV 
    rsync . $(ENV).example.com:/var/www/myapp/ 

Lý do:

  • đó là một đơn giản một-liner
  • nó nhỏ gọn
  • vị trí của nó gần các lệnh mà sử dụng biến

Đừng quên những nhận xét đó là điều quan trọng để gỡ lỗi:

test -n "" 
Makefile:3: recipe for target 'deploy' failed 
make: *** [deploy] Error 1 

... buộc bạn phải tra cứu các Makefile thời gian ...

test -n "" # $ENV 
Makefile:3: recipe for target 'deploy' failed 
make: *** [deploy] Error 1 

... giải thích trực tiếp những gì sai

Biến thể toàn cầu (cho hoàn chỉnh, nhưng không hỏi)

Ngày đầu Makefile của bạn, bạn cũng có thể viết:

ifeq ($(ENV),) 
    $(error ENV is not set) 
endif 

Cảnh báo:

  • không sử dụng tab trong khối đó
  • sử dụng một cách cẩn thận : ngay cả mục tiêu clean sẽ không thành công nếu ENV không được đặt. Nếu không, hãy xem câu trả lời của Hudon phức tạp hơn
+0

Wow. Tôi đã gặp rắc rối với điều này cho đến khi tôi thấy "không sử dụng tab trong khối đó." Cảm ơn bạn! –

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