TL; DR : Use la error
función :
ifndef MY_FLAG
$(error MY_FLAG is not set)
endif
Tenga en cuenta que las líneas no deben sangrarse. Más precisamente, ninguna pestaña debe preceder a estas líneas.
Solución genérica
En caso de que vaya a probar muchas variables, vale la pena definir una función auxiliar para eso:
# 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))))
Y aquí está cómo 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)
Esto generaría un error como este:
Makefile:17: *** Undefined OUT_DIR (build directory). Stop.
Notas:
La verificación real se realiza aquí:
$(if $(value $1),,$(error ...))
Esto refleja el comportamiento del ifndef
condicional, de modo que una variable definida a un valor vacío también se considera "indefinida". Pero esto solo es cierto para variables simples y variables recursivas explícitamente vacías:
# 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)
Como lo sugiere @VictorSergienko en los comentarios, puede desearse un comportamiento ligeramente diferente:
$(if $(value $1)
prueba si el valor no está vacío. A veces está bien si la variable se define con un valor vacío . Yo usaría$(if $(filter undefined,$(origin $1)) ...
Y:
Además, si es un directorio y debe existir cuando se ejecuta la verificación, lo usaría $(if $(wildcard $1))
. Pero sería otra función.
Verificación específica del objetivo
También es posible extender la solución para que se pueda requerir una variable solo si se invoca un determinado objetivo.
$(call check_defined, ...)
desde dentro de la receta
Simplemente mueva el cheque a la receta:
foo :
@:$(call check_defined, BAR, baz value)
El @
signo inicial desactiva el comando que hace eco y :
es el comando real, un trozo de shell no operativo .
Mostrando el nombre del objetivo
La check_defined
función se puede mejorar para generar también el nombre de destino (proporcionado a través de 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 `$@')))
De modo que, ahora una comprobación fallida produce una salida con un formato agradable:
Makefile:7: *** Undefined BAR (baz value) required by target `foo'. Stop.
check-defined-MY_FLAG
objetivo especial
Personalmente, usaría la solución simple y directa anterior. Sin embargo, por ejemplo, esta respuesta sugiere usar un objetivo especial para realizar la verificación real. Se podría tratar de generalizar eso y definir el objetivo como una regla de patrón implícito:
# 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
Observe que check-defined-BAR
se enumera como el requisito previo de solo pedido ( |...
).
Pros:
- (posiblemente) una sintaxis más limpia
Contras:
- No se puede especificar un mensaje de error personalizado
- La ejecución
make -t
(consulte En lugar de ejecutar recetas ) contaminará su directorio raíz con muchos check-defined-...
archivos. Este es un triste inconveniente del hecho de que las reglas de patrón no se pueden declarar.PHONY
.
Creo que estas limitaciones pueden superarse usando algunos hacks de expansióneval
mágicos y secundarios , aunque no estoy seguro de que valga la pena.