TL; DR : Verwenden Sie die error
Funktion :
ifndef MY_FLAG
$(error MY_FLAG is not set)
endif
Beachten Sie, dass die Zeilen nicht eingerückt werden dürfen. Genauer gesagt dürfen vor diesen Zeilen keine Tabulatoren stehen.
Generische Lösung
Wenn Sie viele Variablen testen möchten, lohnt es sich, eine Hilfsfunktion dafür zu definieren:
# 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))))
Und so geht's:
$(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)
Dies würde einen Fehler wie folgt ausgeben:
Makefile:17: *** Undefined OUT_DIR (build directory). Stop.
Anmerkungen:
Die eigentliche Prüfung erfolgt hier:
$(if $(value $1),,$(error ...))
Dies spiegelt das Verhalten der ifndef
Bedingung wider , sodass eine für einen leeren Wert definierte Variable ebenfalls als "undefiniert" betrachtet wird. Dies gilt jedoch nur für einfache Variablen und explizit leere rekursive Variablen:
# 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)
Wie von @VictorSergienko in den Kommentaren vorgeschlagen, kann ein etwas anderes Verhalten erwünscht sein:
$(if $(value $1)
testet, ob der Wert nicht leer ist. Es ist manchmal in Ordnung, wenn die Variable mit einem leeren Wert definiert ist . Ich würde verwenden$(if $(filter undefined,$(origin $1)) ...
Und:
Außerdem , wenn es ein Verzeichnis ist und es muss vorhanden sein, wenn die Prüfung ausgeführt wird, würde ich verwenden $(if $(wildcard $1))
. Wäre aber eine andere Funktion.
Zielspezifische Prüfung
Es ist auch möglich, die Lösung so zu erweitern, dass nur dann eine Variable erforderlich ist, wenn ein bestimmtes Ziel aufgerufen wird.
$(call check_defined, ...)
aus dem Rezept heraus
Verschieben Sie einfach den Scheck in das Rezept:
foo :
@:$(call check_defined, BAR, baz value)
Das führende @
Zeichen schaltet das Echo des Befehls aus und :
ist der eigentliche Befehl, ein Shell- No-Op-Stub .
Zielnamen anzeigen
Die check_defined
Funktion kann verbessert werden, um auch den Zielnamen auszugeben (bereitgestellt durch die $@
Variable):
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 `$@')))
Damit führt eine fehlgeschlagene Prüfung zu einer gut formatierten Ausgabe:
Makefile:7: *** Undefined BAR (baz value) required by target `foo'. Stop.
check-defined-MY_FLAG
spezielles Ziel
Persönlich würde ich die oben beschriebene einfache und unkomplizierte Lösung verwenden. In dieser Antwort wird jedoch beispielsweise vorgeschlagen, ein spezielles Ziel zu verwenden, um die eigentliche Prüfung durchzuführen. Man könnte versuchen, das zu verallgemeinern und das Ziel als implizite Musterregel zu definieren:
# 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 :
Verwendung:
foo :|check-defined-BAR
Beachten Sie, dass dies check-defined-BAR
als Voraussetzung nur für die Bestellung ( |...
) aufgeführt ist.
Vorteile:
- (wohl) eine sauberere Syntax
Nachteile:
- Eine benutzerdefinierte Fehlermeldung kann nicht angegeben werden
- Wenn Sie ausgeführt werden
make -t
(siehe Anstatt Rezepte auszuführen ), wird Ihr Stammverzeichnis mit vielen check-defined-...
Dateien verschmutzt . Dies ist ein trauriger Nachteil der Tatsache, dass Musterregeln nicht deklariert werden können.PHONY
.
Ich glaube, diese Einschränkungen können mit einigen eval
magischen und sekundären Erweiterungs- Hacks überwunden werden , obwohl ich nicht sicher bin, ob es sich lohnt.