TL; DR : użyj error
funkcji :
ifndef MY_FLAG
$(error MY_FLAG is not set)
endif
Zwróć uwagę, że linie nie mogą być wcięte. Dokładniej, żadne tabulatory nie mogą poprzedzać tych wierszy.
Rozwiązanie ogólne
W przypadku, gdy zamierzasz przetestować wiele zmiennych, warto zdefiniować w tym celu funkcję pomocniczą:
# 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))))
A oto jak z niego korzystać:
$(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)
Spowoduje to wyświetlenie następującego błędu:
Makefile:17: *** Undefined OUT_DIR (build directory). Stop.
Uwagi:
Prawdziwe sprawdzenie odbywa się tutaj:
$(if $(value $1),,$(error ...))
Odzwierciedla to zachowanie ifndef
warunku, tak że zmienna zdefiniowana jako pusta wartość jest również uważana za „nieokreśloną”. Ale dotyczy to tylko prostych zmiennych i jawnie pustych zmiennych rekurencyjnych:
# 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)
Jak sugeruje @VictorSergienko w komentarzach, pożądane może być nieco inne zachowanie:
$(if $(value $1)
sprawdza, czy wartość nie jest pusta. Czasami jest OK, jeśli zmienna jest zdefiniowana z pustą wartością . Użyłbym$(if $(filter undefined,$(origin $1)) ...
I:
Co więcej, jeśli jest to katalog i musi istnieć podczas sprawdzania, użyłbym $(if $(wildcard $1))
. Ale byłaby inna funkcja.
Kontrola specyficzna dla celu
Możliwe jest również rozszerzenie rozwiązania tak, aby wymagać zmiennej tylko w przypadku wywołania określonego celu.
$(call check_defined, ...)
od wewnątrz przepisu
Po prostu przenieś czek do przepisu:
foo :
@:$(call check_defined, BAR, baz value)
@
Znak wiodący wyłącza echo polecenia i :
jest faktycznym poleceniem, skrótem powłoki bez operacji .
Wyświetlam nazwę celu
check_defined
Funkcja może poprawić również wysyłać nazwy docelowego (dostarczone przez $@
zmienną)
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 `$@')))
Tak więc, teraz nieudane sprawdzenie daje ładnie sformatowany wynik:
Makefile:7: *** Undefined BAR (baz value) required by target `foo'. Stop.
check-defined-MY_FLAG
specjalny cel
Osobiście skorzystałbym z prostego i prostego rozwiązania powyżej. Jednak na przykład ta odpowiedź sugeruje użycie specjalnego celu do przeprowadzenia faktycznej kontroli. Można by spróbować uogólnić to i zdefiniować cel jako niejawną regułę wzorcową:
# 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 :
Stosowanie:
foo :|check-defined-BAR
Zwróć uwagę, że check-defined-BAR
jest wymieniony jako warunek wstępny dotyczący tylko zamówienia ( |...
).
Plusy:
- (prawdopodobnie) bardziej przejrzysta składnia
Cons:
Uważam, że te ograniczenia można pokonać za pomocą eval
magicznych i dodatkowych hacków rozszerzeń , chociaż nie jestem pewien, czy warto.