Variable Makefile como requisito previo


En un Makefile, una receta deploy necesita una variable de entorno ENV para que se ejecute 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á establecida, por ejemplo: hay una manera de declarar esta variable makefile como un prerrequisito de la receta deploy, como:

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

?

Gracias.

 105
Author: abernier, 2011-01-18

7 answers

Esto causará un error fatal si ENV no está definido y algo 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 sangrados, "error(error" está sangrado con espacios, no una pestaña - controlan lo que hace "ve", teniendo efecto antes de que se ejecute el Makefile.)

 129
Author: Beta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-19 07:09:01

Puede crear un objetivo de guardia implícito, que comprueba que la variable en la raíz está definida, así:

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

Luego agrega un destino guard-ENVVAR en cualquier lugar donde desee afirmar que una variable está definida, de la siguiente manera:

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

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

 70
Author: Clayton Stanley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-03 17:20:32

Variante en línea

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

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

Las razones:

  • es un simple trazador de líneas
  • 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 while ...

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

... explica directamente lo que está mal

Variante global (para completar, pero no se pide)

En la parte superior de su Makefile, también podría escribir:

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

Advertencias:

  • no uses tab en ese bloque
  • use con cuidado: incluso el destino clean fallará si ENV no está establecido. De lo contrario, véase la respuesta de Hudon, que es más compleja
 32
Author: Daniel Alder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-23 07:59:00

Como veo el comando en sí necesita la variable ENV para que pueda comprobarlo 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
 5
Author: ssmir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-18 21:28:34

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

make -j target

Cuando target tiene unas pocas dependencias no garantiza que éstas se ejecuten en un orden dado.

La solución para esto (para garantizar que ENV se revisará antes de elegir las recetas) es verificar ENV durante la primera pasada de make, 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
    ...

Puede leer sobre las diferentes funciones / variables utilizadas aquí y $() es solo una manera de afirmar explícitamente que estamos comparando con "nada".

 3
Author: Hudon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-26 01:02:41

Puede usar ifdef en lugar de un destino 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
 2
Author: Daniel Gallagher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-17 19:46:06

He encontrado que con la mejor respuesta no se puede usar como requisito, excepto para otros objetivos FALSOS. Si se usa como una dependencia para un destino que es un archivo real, usar check-env forzará que ese destino de archivo se reconstruya.

Otras respuestas son globales (por ejemplo, la variable es necesaria para todos los destinos en el Makefile) o usan el shell, por ejemplo, si no hay ENV, make terminaría independientemente del destino.

Una solución que encontré para ambos problemas es

ndef = $(if $(value $(1)),,$(error $(1) not set))

.PHONY: deploy
deploy:
    $(call ndef,ENV)
    echo "deploying $(ENV)"

.PHONY: build
build:
    echo "building"

La salida se ve como

$ make build
echo "building"
building
$ make deploy
Makefile:5: *** ENV not set.  Stop.
$ make deploy ENV="env"
echo "deploying env"
deploying env
$

value tiene algunas advertencias aterradoras, pero para este uso simple creo que es la mejor opción.

 1
Author: 23jodys,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-02 21:53:43