2011-01-18 12 views
84

En un Makefile, una receta deploy necesita una variable de entorno ENV ser configurado para ejecutar correctamente en sí, mientras que otros no les importa, por ejemplo:variable de Makefile como requisito previo

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 esta variable se establece, por ejemplo: ¿hay una forma de declarar esta variable makefile como requisito previo de la receta de despliegue, como:

deploy: make-sure-ENV-variable-is-set 

?

Gracias.

+0

¿Qué quiere decir con "asegúrese de que esta variable esté configurada"? ¿Quiere decir verificar o asegurar? Si no se configuró antes, ¿debería 'hacer 'establecerlo, o dar una advertencia, o generar un error fatal? – Beta

+1

Esta variable debe ser especificada por el usuario, ya que él es el único que conoce su entorno (dev, prod ...) - por ejemplo, al invocar 'make ENV = dev' pero si olvida' ENV = dev ', la receta' deploy' fallará ... – abernier

Respuesta

108

Esto provocará un error fatal si ENV no está definido y algo que lo necesita (en GNUMake, de todos modos).

.PHONY: deploy check-env 

deploy: check-env 
    ... 

other-thing-that-needs-env: check-env 
    ... 

check-env: 
ifndef ENV 
    $(error ENV is undefined) 
endif 

(Tenga en cuenta que ifndef y endif no están sangría, "$ (error" se escribe con márgenes, no una ficha -. they control what make "sees", taking effect before the Makefile is run)

+5

Me aparece 'ENV no está definido' cuando se ejecuta una tarea que ** no ** tiene check-env como requisito previo. – raine

+0

@rane: Eso es interesante. ¿Puedes dar un ejemplo completo mínimo? – Beta

+0

Aquí, https://gist.github.com/raneksi/5579022 – raine

2

Puede usar ifdef en lugar de un objetivo diferente.

.PHONY: deploy 
deploy: 
    ifdef ENV 
     rsync . $(ENV).example.com:/var/www/myapp/ 
    else 
     @echo 1>&2 "ENV must be set" 
     false       # Cause deploy to fail 
    endif 
+0

Hola, gracias por tu respuesta, pero no puedo aceptarlo debido a un código duplicado que tu sugerencia genera ... aún más 'deploy' no es la única receta que tiene que verificar el 'ENV' variable de estado. – abernier

+0

y luego simplemente refactorizar. Utilice las instrucciones '.PHONY: deploy' y' deploy: 'antes del bloque ifdef y elimine la duplicación. (Por cierto, he editado la respuesta para reflejar el método correcto) –

5

Como veo el comando en sí necesita la variable ENV para que pueda comprobar en el propio comando:

.PHONY: deploy check-env 

deploy: check-env 
    rsync . $(ENV).example.com:/var/www/myapp/ 

check-env: 
    if test "$(ENV)" = "" ; then \ 
     echo "ENV not set"; \ 
     exit 1; \ 
    fi 
+0

El problema con esto es que 'deploy' no es necesariamente la única receta que necesita esta variable. Con esta solución, tengo que probar el estado de 'ENV' para cada uno de uno ... mientras que me gustaría tratar con él como un requisito único (tipo de). – abernier

+0

@abernier Se ha actualizado la respuesta – ssmir

56

Se puede crear un objetivo de protección implícita, que comprueba que el variable en el tallo se define, como esto:

guard-%: 
    @ if [ "${${*}}" = "" ]; then \ 
     echo "Environment variable $* not set"; \ 
     exit 1; \ 
    fi 

a continuación, agregue un objetivo guardia-ENVVAR cualquier lugar que desee para afirmar que se define una variable, como esto:

change-hostname: guard-HOSTNAME 
     ./changeHostname.sh ${HOSTNAME} 

Si llama 'make change-hostname', sin agregar HOSTNAME = somehostname en la llamada, obtendrá un error y la compilación fallará.

+3

Esa es una solución inteligente, me gusta :) –

+0

Sé que esta es una respuesta antigua, pero tal vez alguien todavía está viendo de lo contrario, podría volver a publicar esto como una nueva pregunta ... Estoy tratando de implementar este objetivo implícito "guard" para verificar las variables de entorno establecidas y funciona en principio; sin embargo, los comandos de la regla "guard-%" se imprimen realmente en el shell. Esto me gustaría suprimir. ¿Cómo es esto posible? – genomicsio

+2

OK. encontré la solución yo mismo ... @ al comienzo de las líneas de comando de la regla es mi amigo ... – genomicsio

3

Un posible problema con las respuestas dadas hasta el momento es que el orden de dependencia en make no está definido. Por ejemplo, ejecutando:

make -j target 

cuando target tiene algunas dependencias no garantiza que éstas se ejecutarán en cualquier orden dado.

La solución para esto (para garantizar que la ENV se comprueba antes se eligen recetas) es comprobar ENV en la primera pasada de maquillaje, fuera de cualquier receta:

## Are any of the user's goals dependent on ENV? 
ifneq ($(filter deploy other-thing-that-needs-ENV,$(MAKECMDGOALS)),$()) 
ifndef ENV 
$(error ENV not defined) 
endif 
endif 

.PHONY: deploy 

deploy: foo bar 
    ... 

other-thing-that-needs-ENV: bar baz bono 
    ... 

se puede leer sobre las diferentes funciones/las variables utilizadas here y $() son solo una forma de indicar explícitamente que estamos comparando contra "nada".

20

Inline variante

En mis makefiles, normalmente utilizo una expresión como:

deploy: 
    test -n "$(ENV)" # $$ENV 
    rsync . $(ENV).example.com:/var/www/myapp/ 

Las razones:

  • Es un simple de una sola línea
  • es compacto
  • se encuentra cerca de los comandos que utilizan la variable

No olvide el comentario que es importante para la depuración:

test -n "" 
Makefile:3: recipe for target 'deploy' failed 
make: *** [deploy] Error 1 

... te obliga a buscar el Makefile tiempo ...

test -n "" # $ENV 
Makefile:3: recipe for target 'deploy' failed 
make: *** [deploy] Error 1 

... explica directamente lo que está mal

variante Global (por exhaustividad, pero no se le preguntó)

En la parte superior de su Makefile, también se puede escribir:

ifeq ($(ENV),) 
    $(error ENV is not set) 
endif 

Advertencias:

  • pestaña no utilice en ese bloque
  • uso con cuidado : incluso el objetivo clean fallará si ENV no está configurado. De lo contrario, vea la respuesta de Hudon que es más compleja
+0

Wow. Estaba teniendo problemas con esto hasta que vi "no usar la pestaña en ese bloque". ¡Gracias! –

Cuestiones relacionadas