TL; DR : utilizzare la error
funzione :
ifndef MY_FLAG
$(error MY_FLAG is not set)
endif
Si noti che le righe non devono essere rientrate. Più precisamente, nessuna scheda deve precedere queste righe.
Soluzione generica
Nel caso in cui testerai molte variabili, vale la pena definire una funzione ausiliaria per questo:
# 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))))
Ed ecco come usarlo:
$(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)
Ciò produrrebbe un errore come questo:
Makefile:17: *** Undefined OUT_DIR (build directory). Stop.
Appunti:
Il vero controllo è fatto qui:
$(if $(value $1),,$(error ...))
Ciò riflette il comportamento del ifndef
condizionale, in modo che anche una variabile definita su un valore vuoto sia considerata "non definita". Questo è vero solo per variabili semplici e variabili ricorsive esplicitamente vuote:
# 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)
Come suggerito da @VictorSergienko nei commenti, può essere desiderato un comportamento leggermente diverso:
$(if $(value $1)
verifica se il valore non è vuoto. A volte è OK se la variabile è definita con un valore vuoto . Vorrei usare$(if $(filter undefined,$(origin $1)) ...
E:
Inoltre, se si tratta di una directory e deve esistere quando viene eseguito il controllo, utilizzerei $(if $(wildcard $1))
. Ma sarebbe un'altra funzione.
Controllo specifico per target
È anche possibile estendere la soluzione in modo da poter richiedere una variabile solo se viene invocato un determinato target.
$(call check_defined, ...)
dall'interno della ricetta
Basta spostare il segno di spunta nella ricetta:
foo :
@:$(call check_defined, BAR, baz value)
Il @
segno principale disattiva l'eco del comando ed :
è il comando effettivo, uno stub no-op della shell .
Mostra il nome target
La check_defined
funzione può essere migliorata per generare anche il nome di destinazione (fornito attraverso la $@
variabile):
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 `$@')))
Quindi, ora un controllo non riuscito produce un output ben formattato:
Makefile:7: *** Undefined BAR (baz value) required by target `foo'. Stop.
check-defined-MY_FLAG
bersaglio speciale
Personalmente userei la soluzione semplice e diretta sopra. Tuttavia, ad esempio, questa risposta suggerisce di utilizzare un obiettivo speciale per eseguire il controllo effettivo. Si potrebbe provare a generalizzare questo e definire il target come una regola del modello implicito:
# 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 :
Uso:
foo :|check-defined-BAR
Si noti che il check-defined-BAR
è elencato come prerequisito per il solo ordine ( |...
).
Professionisti:
- (discutibilmente) una sintassi più pulita
Contro:
Credo che queste limitazioni possano essere superate usando alcuni hack eval
magici e di espansione secondaria , anche se non sono sicuro che ne valga la pena.