makefile - phony - Anula el archivo MAKE si la variable no está establecida
makefile windows (3)
Use la test
función de shell:
foo:
test $(something)
Uso:
$ make foo
test
Makefile:2: recipe for target ''foo'' failed
make: *** [foo] Error 1
$ make foo something=x
test x
¿Cómo podría abortar una ejecución de make / makefile en función de que la variable de un archivo MAKE no se haya establecido / valorado?
Se me ocurrió esto, pero funciona solo si la persona que llama no ejecuta explícitamente un objetivo (es decir, ejecuta solo).
ifeq ($(MY_FLAG),)
abort: ## This MUST be the first target :( ugly
@echo Variable MY_FLAG not set && false
endif
all:
@echo MY_FLAG=$(MY_FLAG)
Creo que algo así sería una buena idea, pero no encontré nada en el manual de make:
ifndef MY_FLAG
.ABORT
endif
Utilice el manejo de errores de shell para las variables no establecidas (tenga en cuenta el doble $
):
$ cat Makefile
foo:
echo "something is set to $${something:?}"
$ make foo
echo "something is set to ${something:?}"
/bin/sh: something: parameter null or not set
make: *** [foo] Error 127
$ make foo something=x
echo "something is set to ${something:?}"
something is set to x
Si necesita un mensaje de error personalizado, agréguelo después de ?
:
$ cat Makefile
hello:
echo "hello $${name:?please tell me who you are via /$$name}"
$ make hello
echo "hello ${name:?please tell me who you are via /$name}"
/bin/sh: name: please tell me who you are via $name
make: *** [hello] Error 127
$ make hello name=jesus
echo "hello ${name:?please tell me who you are via /$name}"
hello jesus
TL; DR : use la función de error
:
ifndef MY_FLAG
$(error MY_FLAG is not set)
endif
Tenga en cuenta que las líneas no deben estar sangradas. Más precisamente, no deben aparecer pestañas delante de 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.
Control específico del objetivo
También es posible ampliar la solución para que uno pueda requerir una variable solo si se invoca un determinado objetivo.
$(call check_defined, ...)
desde el interior de la receta
Simplemente mueva el cheque a la receta:
foo :
@:$(call check_defined, BAR, baz value)
El signo @
inicial apaga el eco del comando y :
es el comando real, un código auxiliar sin shell.
Mostrando nombre de destino
La función check_defined
se puede mejorar para generar también el nombre del objetivo (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 `$@'')))
Entonces, ahora un chequeo fallido produce un resultado muy formateado:
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 el uso de un objetivo especial para realizar el control real. Uno 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 order-only ( |...
).
Pros:
- (discutible) una sintaxis más limpia
Contras:
- No se puede especificar un mensaje de error personalizado
- Ejecutar
make -t
(ver en lugar de ejecutar recetas ) contaminará tu directorio raíz con muchos archivoscheck-defined-...
Este es un triste inconveniente del hecho de que las reglas de patrones no se pueden declarar.PHONY
.
Creo que estas limitaciones se pueden superar usando algunas magic eval
y hacks secundarios de expansión , aunque no estoy seguro de que valga la pena.