En un Makefile, una deployreceta necesita ENVque se configure una variable de entorno para ejecutarse correctamente, mientras que a otros no les importa, por ejemplo:
ENV =
.PHONY: deploy hello
deploy:
rsync . $(ENV).example.com:/var/www/myapp/
hello:
echo "I don't care about ENV, just saying hello!"
¿Cómo puedo asegurarme de que esta variable esté configurada?
deploy: make-sure-ENV-variable-is-set
?
Gracias.

makeconfigurarlo, dar una advertencia o generar un error fatal?make ENV=devpero si se olvidaENV=dev, ladeployreceta fallará ...Respuestas:
Esto causará un error fatal si
ENVno está definido y algo lo necesita (en GNUMake, de todos modos).(Tenga en cuenta que si ifndef y endif no están sangrados, controlan lo que hace "ve" , surten efecto antes de que se ejecute el Makefile. "$ (Error" está sangrado con una pestaña para que solo se ejecute en el contexto de la regla).
fuente
ENV is undefinedcuando ejecuto una tarea que no tiene check-env como requisito previo.check-envregla; Make no lo expandirá a menos que / hasta que ejecute la regla. Si no comienza con una TAB (como en el ejemplo de @ rane), Make lo interpreta como si no estuviera en una regla y lo evalúa antes de ejecutar cualquier regla, independientemente del objetivo.Puede crear un objetivo de protección implícito, que verifique que la variable en la raíz esté definida, así:
Luego agrega un
guard-ENVVARobjetivo en cualquier lugar donde desee afirmar que una variable está definida, como esta:Si llama
make change-hostname, sin agregarHOSTNAME=somehostnamela llamada, obtendrá un error y la compilación fallará.fuente
if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fiDVariante en línea
En mis archivos MAKE, normalmente uso una expresión como:
Las razones:
No olvide el comentario que es importante para la depuración:
... te obliga a buscar el Makefile mientras ...
... explica directamente lo que está mal
Variante global (para completar, pero no solicitada)
Además de tu Makefile, también puedes escribir:
Advertencias:
cleanobjetivo fallará si no se establece ENV. De lo contrario, vea la respuesta de Hudon, que es más complejafuente
@. -> gnu.org/software/make/manual/make.html#Echoing@test -n "$(name)" || (echo 'A name must be defined for the backup. Ex: make backup name=xyz' && exit 1)Un posible problema con las respuestas dadas hasta ahora es que el orden de dependencia en make no está definido. Por ejemplo, ejecutando:
cuando
targettiene algunas dependencias no garantiza que se ejecutarán en un orden determinado.La solución para esto (para garantizar que se verifique el ENV antes de elegir las recetas) es verificar el ENV durante la primera pasada, fuera de cualquier receta:
Puede leer sobre las diferentes funciones / variables utilizadas aquí y
$()es solo una forma de declarar explícitamente que estamos comparando con "nada".fuente
He encontrado que la mejor respuesta no se puede usar como un requisito, a excepción de otros objetivos PHONY. Si se usa como una dependencia para un objetivo que es un archivo real, el uso
check-envforzará la reconstrucción del objetivo del archivo.Otras respuestas son globales (por ejemplo, la variable se requiere para todos los objetivos en el Makefile) o usan el shell, por ejemplo, si faltaba ENV, make terminaría independientemente del objetivo.
Una solución que encontré para ambos problemas es
La salida se ve como
valuetiene algunas advertencias de miedo, pero para este uso simple, creo que es la mejor opción.fuente
Como veo, el comando en sí necesita la variable ENV para que pueda verificarlo en el comando en sí:
fuente
deployno es necesariamente la única receta que necesita esta variable. Con esta solución, tengo que probar el estado deENVcada uno ... mientras me gustaría tratarlo como un prerrequisito único (más o menos).Sé que esto es viejo, pero pensé en compartir con mis propias experiencias para futuros visitantes, ya que es un poco más ordenado en mi humilde opinión.
Normalmente,
makese usaráshcomo su shell predeterminado ( establecido a través de laSHELLvariable especial ). Enshy sus derivados, es trivial salir con un mensaje de error al recuperar una variable de entorno si no se establece o es nulo al hacer:${VAR?Variable VAR was not set or null}.Extendiendo esto, podemos escribir un objetivo de fabricación reutilizable que se puede utilizar para fallar otros objetivos si no se estableció una variable de entorno:
Cosas de nota:
$$requiere el signo de dólar escapado ( ) para diferir la expansión al shell en lugar de dentro demaketestes solo para evitar que el shell intente ejecutar el contenido deVAR(no sirve para ningún otro propósito significativo).check-env-varsse puede extender trivialmente para buscar más variables de entorno, cada una de las cuales agrega solo una línea (por ejemplo@test $${NEWENV?Please set environment variable NEWENV})fuente
ENVcontiene espacios, esto parece fallar (al menos para mí)Puede usar en
ifdeflugar de un objetivo diferente.fuente
deployno es la única receta que tiene que verificar laENVvariable de estado..PHONY: deployydeploy:antes del bloque ifdef y elimine la duplicación. (por cierto, he editado la respuesta para reflejar el método correcto)