TL; DR : utilisez la error
fonction :
ifndef MY_FLAG
$(error MY_FLAG is not set)
endif
Notez que les lignes ne doivent pas être indentées. Plus précisément, aucun onglet ne doit précéder ces lignes.
Solution générique
Dans le cas où vous allez tester de nombreuses variables, il vaut la peine de définir une fonction auxiliaire pour cela:
# 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))))
Et voici comment l'utiliser:
$(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)
Cela produirait une erreur comme celle-ci:
Makefile:17: *** Undefined OUT_DIR (build directory). Stop.
Remarques:
Le vrai contrôle se fait ici:
$(if $(value $1),,$(error ...))
Cela reflète le comportement du ifndef
conditionnel, de sorte qu'une variable définie à une valeur vide est également considérée comme "non définie". Mais cela n'est vrai que pour les variables simples et les variables récursives explicitement vides:
# 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)
Comme suggéré par @VictorSergienko dans les commentaires, un comportement légèrement différent peut être souhaité:
$(if $(value $1)
teste si la valeur n'est pas vide. C'est parfois OK si la variable est définie avec une valeur vide . J'utiliserais$(if $(filter undefined,$(origin $1)) ...
Et:
De plus, si c'est un répertoire et qu'il doit exister lorsque la vérification est exécutée, j'utiliserais $(if $(wildcard $1))
. Mais ce serait une autre fonction.
Vérification spécifique à la cible
Il est également possible d'étendre la solution afin que l'on puisse exiger une variable uniquement si une certaine cible est invoquée.
$(call check_defined, ...)
de l'intérieur de la recette
Déplacez simplement le chèque dans la recette:
foo :
@:$(call check_defined, BAR, baz value)
Le @
signe principal désactive l'écho de commande et :
est la commande réelle, un stub no-op du shell .
Affichage du nom de la cible
La check_defined
fonction peut être améliorée pour afficher également le nom de la cible (fourni via la $@
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 `$@')))
Donc, maintenant, une vérification échouée produit une sortie bien formatée:
Makefile:7: *** Undefined BAR (baz value) required by target `foo'. Stop.
check-defined-MY_FLAG
cible spéciale
Personnellement, j'utiliserais la solution simple et directe ci-dessus. Cependant, par exemple, cette réponse suggère d'utiliser une cible spéciale pour effectuer le contrôle réel. On pourrait essayer de généraliser cela et de définir la cible comme une règle de modèle implicite:
# 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 :
Usage:
foo :|check-defined-BAR
Notez que le check-defined-BAR
est répertorié comme condition préalable à la commande uniquement ( |...
).
Avantages:
- (sans doute) une syntaxe plus propre
Les inconvénients:
Je crois que ces limitations peuvent être surmontées en utilisant des hacks d' expansioneval
magiques et secondaires , même si je ne suis pas sûr que cela en vaille la peine.