Como definir a variável de ambiente do processo filho no Makefile

135

Gostaria de mudar 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

para:

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

Infelizmente, o segundo não funciona (o processo do nó ainda é executado com o padrão NODE_ENV.

Do que eu senti falta?

bodokaiser
fonte

Respostas:

153

As variáveis ​​make não são exportadas para o ambiente dos processos make chama ... por padrão. No entanto, você pode usar o make's exportpara forçá-los a fazê-lo. Mudança:

test: NODE_ENV = test

para isso:

test: export NODE_ENV = test

(supondo que você tenha uma versão suficientemente moderna do GNU make> = 3.77).

Cientista maluco
fonte
3
Eu tenho o GNU make 3.81 e all: <\n\t>export PROJ_ROOT=$(CURDIR)<\n\t>echo $(PROJ_ROOT)<\n>gera a expansão correta para a primeira linha, mas apenas echopara a segunda. PROJ_ROOTnão está definido após a execução do make. Os espaços ao redor =dão "nome de variável inválido" para exportação. Ter a primeira linha como pré-requisito, como no seu exemplo, fornece "comandos iniciados antes do primeiro destino"
Gauthier
8
@ Gauthier sim, é claro. Não foi isso que escrevi. Você adicionou um <\ n \ t> após o all:, o que não está no meu exemplo. Meu exemplo deve ser usado como está escrito: está definindo uma variável específica do alvo, NÃO adicionando um comando à receita. Além disso, você não pode usar uma receita e uma variável específica do alvo em um alvo ao mesmo tempo: você deve escrever o alvo duas vezes. Veja o segundo exemplo da pergunta e faça uma nova pergunta se isso não ajudar a explicá-la: não há espaço ou formatação suficiente nos comentários.
MadScientist 30/10
1
E sobre várias variáveis?
holms
1
Tudo bem, mas você o adicionou à cabeça do alvo. Apenas listá-los no contexto do destino não funcionará? Porque ele não funciona para mim
holms
2
Variáveis ​​específicas de alvo foram adicionadas no GNU make 3.77. Eles são exportáveis ​​a partir do GNU make 3.81. Veja git.savannah.gnu.org/cgit/make.git/tree/NEWS
MadScientist
79

Como o MadScientist apontou , você pode exportar variáveis ​​individuais com:

export MY_VAR = foo  # Available for all targets

Ou exporte variáveis ​​para um destino específico ( variáveis ​​específicas do destino ):

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

Você também pode especificar o .EXPORT_ALL_VARIABLESdestino para - você adivinhou! - EXPORTAR TODAS AS COISAS !!!:

.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

consulte .EXPORT_ALL_VARIABLES

Shammel Lee
fonte
2
Curiosamente eu fiz teste mais cedo que mostrou que funcionou .. (não sei por que agora ..) Eu posso voltar e apagar o comentário Eu acho que ..
AnthonyC
3
@AnthonyC Ele funciona porque há dois MY_VARs: um é variável makefile acessado como ${MY_VAR}e outra é o bash exportados variável, acessado como$$MY_VAR
Sergei
Útil. Mas não é possível encontrar uma maneira de exportar apenas um conjunto de variáveis.
Eric Chen
15

Eu só precisava das variáveis ​​de ambiente localmente para invocar meu comando de teste, aqui está um exemplo de configuração de vários vars de ambiente em um shell bash e escapando do sinal de cifrão make.

SHELL := /bin/bash

.PHONY: test tests
test tests:
    PATH=./node_modules/.bin/:$$PATH \
    JSCOVERAGE=1 \
    nodeunit tests/
ThorSummoner
fonte
6
Edite sua resposta para incluir algumas explicações. As respostas somente de código fazem muito pouco para educar futuros leitores de SO. Sua resposta está na fila de moderação por ser de baixa qualidade.
precisa saber é o seguinte
ThorSummoner, esta solução não é tão flexível quanto a abordagem acima. Por exemplo, pode-se desejar ter uma única regra para chamar um comando e várias outras regras que modificam esse comportamento, definindo variáveis ​​de ambiente. Considere: test: cmd perf: export PERF = "yes" perf: test Se 'cmd' for complicado (e geralmente é), essa abordagem será muito mais fácil de manter. Sua abordagem para definir a variável de ambiente na regra cmd torna isso mais difícil.
26517 Keith Hanlan
1

Reescreveria o teste de destino original, cuidando para que a variável necessária seja definida NO MESMO SUB-PROCESSO como o aplicativo a ser iniciado:

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