TL; DR : error
Fonksiyonu kullanın :
ifndef MY_FLAG
$(error MY_FLAG is not set)
endif
Satırların girintili olmaması gerektiğini unutmayın. Daha doğrusu, bu satırlardan önce hiçbir sekme olmamalıdır.
Genel çözüm
Birçok değişkeni test edecekseniz, bunun için yardımcı bir işlev tanımlamaya değer:
# Check that given variables are set and all have non-empty values,
# die with an error otherwise.
#
# Params:
# 1. Variable name(s) to test.
# 2. (optional) Error message to print.
check_defined = \
$(strip $(foreach 1,$1, \
$(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
$(if $(value $1),, \
$(error Undefined $1$(if $2, ($2))))
Ve işte nasıl kullanılacağı:
$(call check_defined, MY_FLAG)
$(call check_defined, OUT_DIR, build directory)
$(call check_defined, BIN_DIR, where to put binary artifacts)
$(call check_defined, \
LIB_INCLUDE_DIR \
LIB_SOURCE_DIR, \
library path)
Bu, şöyle bir hata üretir:
Makefile:17: *** Undefined OUT_DIR (build directory). Stop.
Notlar:
Gerçek kontrol burada yapılır:
$(if $(value $1),,$(error ...))
Bu, ifndef
koşullu davranışı yansıtır , böylece boş bir değere tanımlanan bir değişken de "tanımsız" olarak kabul edilir. Ancak bu sadece basit değişkenler ve açıkça boş yinelemeli değişkenler için geçerlidir:
# ifndef and check_defined consider these UNDEFINED:
explicitly_empty =
simple_empty := $(explicitly_empty)
# ifndef and check_defined consider it OK (defined):
recursive_empty = $(explicitly_empty)
Yorumlarda @VictorSergienko tarafından önerildiği gibi, biraz farklı bir davranış istenebilir:
$(if $(value $1)
değerin boş olup olmadığını test eder. Değişken boş bir değerle tanımlanırsa bazen sorun olmaz . Kullanırdım$(if $(filter undefined,$(origin $1)) ...
Ve:
Ayrıca, eğer bu bir dizin ve kontrol çalıştırıldığında var olması gerekir , ben kullanmak istiyorum $(if $(wildcard $1))
. Ama başka bir işlev olurdu.
Hedefe özgü kontrol
Çözümü, yalnızca belirli bir hedef çağrıldığında değişken gerektirebilecek şekilde genişletmek de mümkündür.
$(call check_defined, ...)
tarifin içinden
Sadece çekleri tarife taşıyın:
foo :
@:$(call check_defined, BAR, baz value)
Önde gelen @
işaret, komut yankısını kapatır ve :
gerçek komuttur, bir kabuk no-op saplamasıdır .
Hedef adı gösteriliyor
check_defined
İşlevi de çıkış (sağlanan hedef ismi geliştirilebilir $@
değişken):
check_defined = \
$(strip $(foreach 1,$1, \
$(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
$(if $(value $1),, \
$(error Undefined $1$(if $2, ($2))$(if $(value @), \
required by target `$@')))
Böylece, başarısız bir kontrol güzelce biçimlendirilmiş bir çıktı üretir:
Makefile:7: *** Undefined BAR (baz value) required by target `foo'. Stop.
check-defined-MY_FLAG
özel hedef
Şahsen yukarıdaki basit ve anlaşılır çözümü kullanırdım. Bununla birlikte, örneğin, bu cevap , gerçek kontrolü gerçekleştirmek için özel bir hedef kullanmanızı önerir. Bunu genellemeye çalışabilir ve hedefi örtük bir kalıp kuralı olarak tanımlayabiliriz:
# Check that a variable specified through the stem is defined and has
# a non-empty value, die with an error otherwise.
#
# %: The name of the variable to test.
#
check-defined-% : __check_defined_FORCE
@:$(call check_defined, $*, target-specific)
# Since pattern rules can't be listed as prerequisites of .PHONY,
# we use the old-school and hackish FORCE workaround.
# You could go without this, but otherwise a check can be missed
# in case a file named like `check-defined-...` exists in the root
# directory, e.g. left by an accidental `make -t` invocation.
.PHONY : __check_defined_FORCE
__check_defined_FORCE :
Kullanımı:
foo :|check-defined-BAR
Bunun yalnızca sipariş ( ) önkoşulu check-defined-BAR
olarak listelendiğine dikkat edin .|...
Artıları:
- (tartışmasız) daha temiz bir sözdizimi
Eksileri:
Ben buna değdiğinden emin olmasam da , bu sınırlamaların bazı eval
sihirli ve ikincil genişletme saldırıları kullanılarak aşılabileceğine inanıyorum .