Cómo configurar la variable de entorno del proceso hijo en Makefile

135

Me gustaría cambiar este Makefile:

SHELL := /bin/bash
PATH  := node_modules/.bin:$(PATH)

boot:
    @supervisor         \
      --harmony         \
      --watch etc,lib       \
      --extensions js,json      \
      --no-restart-on error     \
        lib

test:
    NODE_ENV=test mocha         \
      --harmony             \
      --reporter spec       \
        test

clean:
    @rm -rf node_modules

.PHONY: test clean

a:

SHELL := /bin/bash
PATH  := node_modules/.bin:$(PATH)

boot:
    @supervisor         \
      --harmony         \
      --watch etc,lib       \
      --extensions js,json      \
      --no-restart-on error     \
        lib

test: NODE_ENV=test
test:
    mocha                   \
      --harmony             \
      --reporter spec       \
        test

clean:
    @rm -rf node_modules

.PHONY: test clean

Lamentablemente, el segundo no funciona (el proceso de nodo todavía se ejecuta con el valor predeterminado NODE_ENV.

¿Qué me perdí?

bodokaiser
fuente

Respuestas:

153

Las variables de creación no se exportan al entorno de procesos que realizan invocaciones ... de forma predeterminada. Sin embargo, puede usar make exportpara obligarlos a hacerlo. Cambio:

test: NODE_ENV = test

a esto:

test: export NODE_ENV = test

(suponiendo que tenga una versión suficientemente moderna de GNU make> = 3.77).

Científico loco
fuente
3
Tengo GNU make 3.81, y all: <\n\t>export PROJ_ROOT=$(CURDIR)<\n\t>echo $(PROJ_ROOT)<\n>genera la expansión correcta para la primera fila, pero solo echopara la segunda. PROJ_ROOTno se establece después de ejecutar make. Los espacios alrededor =dan "nombre de variable incorrecto" para la exportación. Tener la primera fila como prerrequisito como en su ejemplo da "los comandos comienzan antes del primer objetivo"
Gauthier
8
@Gauthier sí, por supuesto. Eso no es lo que escribí. Agregó un <\ n \ t> después del all:, que no está en mi ejemplo. Mi ejemplo está destinado a usarse como está escrito: está definiendo una variable específica del objetivo, NO agregando un comando a la receta. Además, no puede usar una receta y una variable específica del objetivo en un objetivo al mismo tiempo: debe escribir el objetivo dos veces. Vea el segundo ejemplo en la pregunta y haga una nueva pregunta si esto no ayuda a explicarlo: no hay suficiente espacio o formato en los comentarios.
MadScientist
1
¿Qué pasa con las variables múltiples?
holms
1
Eso está bien, pero lo agregaste a la cabeza del objetivo. ¿Simplemente enumerarlos en el contexto del objetivo no funcionará? Porque no funciona para mí
holms
2
Se agregaron variables específicas de destino en GNU make 3.77. Son exportables a partir de GNU make 3.81. Ver git.savannah.gnu.org/cgit/make.git/tree/NEWS
MadScientist el
79

Como señaló MadScientist , puede exportar variables individuales con:

export MY_VAR = foo  # Available for all targets

O exportar variables para un objetivo específico ( variables específicas del objetivo ):

my-target: export MY_VAR_1 = foo
my-target: export MY_VAR_2 = bar
my-target: export MY_VAR_3 = baz

my-target: dependency_1 dependency_2
  echo do something

También puede especificar el .EXPORT_ALL_VARIABLESobjetivo para, ¡lo adivinó! ¡EXPORTAR TODAS LAS COSAS!

.EXPORT_ALL_VARIABLES:

MY_VAR_1 = foo
MY_VAR_2 = bar
MY_VAR_3 = baz

test:
  @echo $$MY_VAR_1 $$MY_VAR_2 $$MY_VAR_3

ver .EXPORT_ALL_VARIABLES

Shammel Lee
fuente
2
Por extraño que parezca, lo probé antes y demostró que funcionó ... (no estoy seguro de por qué ahora ...) Puedo volver y eliminar el comentario, supongo ...
AnthonyC
3
@AnthonyC Funciona porque hay dos MY_VARs: uno es variable de archivo MAKE accedido como ${MY_VAR}y otro es variable exportada bash, accedido como$$MY_VAR
Sergei
Útil. Pero no puede encontrar una manera de exportar solo un conjunto de variables.
Eric Chen
15

Solo necesitaba las variables de entorno localmente para invocar mi comando de prueba, aquí hay un ejemplo que configura varios vars de entorno en un shell bash y escapa del signo de dólar make.

SHELL := /bin/bash

.PHONY: test tests
test tests:
    PATH=./node_modules/.bin/:$$PATH \
    JSCOVERAGE=1 \
    nodeunit tests/
ThorSummoner
fuente
66
Edite su respuesta para incluir alguna explicación. Las respuestas de solo código hacen muy poco para educar a los futuros lectores de SO. Su respuesta está en la cola de moderación por ser de baja calidad.
mickmackusa
ThorSummoner, esta solución no es tan flexible como el enfoque anterior. Por ejemplo, uno podría desear tener una sola regla para invocar un comando y luego varias otras reglas que modifiquen ese comportamiento estableciendo variables de entorno. Considere: test: cmd perf: export PERF = "yes" perf: test Si 'cmd' es complicado (y generalmente lo es), entonces este enfoque es mucho más fácil de mantener. Su enfoque para establecer la variable de entorno en la regla de cmd lo hace más difícil.
Keith Hanlan
1

Volvería a escribir la prueba de destino original, teniendo cuidado de que la variable necesaria se defina EN EL MISMO SUBPROCESO como la aplicación que se iniciará:

test:
    ( NODE_ENV=test mocha --harmony --reporter spec test )
Guiyo M
fuente