Come impostare la variabile di ambiente del processo figlio in Makefile


135

Vorrei cambiare questo 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

per:

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

Sfortunatamente il secondo non funziona (il processo del nodo funziona ancora con il valore predefinito NODE_ENV.

Cosa mi sono perso?

Risposte:


153

Le variabili Make non vengono esportate nell'ambiente dei processi make invoke ... per impostazione predefinita. Comunque puoi usare make's exportper costringerli a farlo. Modificare:

test: NODE_ENV = test

a questa:

test: export NODE_ENV = test

(supponendo che tu abbia una versione sufficientemente moderna di GNU make> = 3.77).


3
Ho GNU fatto 3.81, e all: <\n\t>export PROJ_ROOT=$(CURDIR)<\n\t>echo $(PROJ_ROOT)<\n>genera l'espansione corretta per la prima riga, ma solo echoper la seconda. PROJ_ROOTnon è impostato dopo aver eseguito make. Gli spazi intorno =danno "nome variabile errato" per l'esportazione. Avere la prima riga come prerequisito come nel tuo esempio dà "i comandi iniziano prima del primo obiettivo"
Gauthier,

8
@Gauthier sì, certo. Non è quello che ho scritto. Hai aggiunto un <\ n \ t> dopo il all:, che non è nel mio esempio. Il mio esempio deve essere usato come scritto: sta definendo una variabile specifica del target, NON aggiungendo un comando alla ricetta. Inoltre non è possibile utilizzare contemporaneamente una ricetta e una variabile specifica del target su un target: è necessario scrivere il target due volte. Vedi il secondo esempio nella domanda e fai una nuova domanda se questo non aiuta a spiegarlo: non c'è abbastanza spazio o formattazione nei commenti.
MadScientist,

1
Che dire di più variabili?
holms,

1
Va bene, ma l'hai aggiunto alla testa del bersaglio. Basta elencarli nel contesto del target non funzionerà? Perché non funziona per me
holms,

2
Le variabili specifiche del target sono state aggiunte in GNU a 3.77. Sono esportabili a partire da GNU 3.81. Vedi git.savannah.gnu.org/cgit/make.git/tree/NEWS
MadScientist,

79

Come sottolineato da MadScientist , è possibile esportare singole variabili con:

export MY_VAR = foo  # Available for all targets

O variabili di esportazione per un target specifico ( variabili target-specifici ):

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

Puoi anche specificare l' .EXPORT_ALL_VARIABLESobiettivo a — hai indovinato! —ESPORTA TUTTE LE COSE !!!:

.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

vedi .EXPORT_ALL_VARIABLES


2
Stranamente l'ho provato prima che ha dimostrato che funzionava .. (non so perché ora ..) Posso tornare indietro ed eliminare il commento immagino ..
AnthonyC

3
@AnthonyC Funziona perché ci sono due MY_VARs: uno è una variabile makefile a cui si accede ${MY_VAR}e un altro è una variabile esportata bash, a cui si accede come$$MY_VAR
Sergei

Utile. Ma non riesco a trovare un modo per esportare solo un insieme di variabili.
Eric Chen,

15

Avevo solo bisogno delle variabili di ambiente a livello locale per invocare il mio comando test, ecco un esempio che imposta più var di ambiente in una shell bash e sfugge al segno del dollaro make.

SHELL := /bin/bash

.PHONY: test tests
test tests:
    PATH=./node_modules/.bin/:$$PATH \
    JSCOVERAGE=1 \
    nodeunit tests/

6
Modifica la tua risposta per includere alcune spiegazioni. Le risposte solo al codice fanno ben poco per educare i futuri lettori SO. La tua risposta è nella coda di moderazione per essere di bassa qualità.
mickmackusa,

ThorSummoner, questa soluzione non è flessibile come l'approccio sopra. Ad esempio, si potrebbe desiderare di avere una sola regola per invocare un comando e quindi diverse altre regole che modificano quel comportamento impostando le variabili di ambiente. Considerare: test: cmd perf: export PERF = "yes" perf: test Se 'cmd' è complicato (e di solito lo è), questo approccio è molto più facile da mantenere. Il tuo approccio all'impostazione della variabile d'ambiente nella regola cmd rende questo più difficile.
Keith Hanlan,

1

Riscriverei il test target originale, avendo cura che la variabile necessaria sia definita NELLO STESSO SOTTO-PROCESSO come l'applicazione da avviare:

test:
    ( NODE_ENV=test mocha --harmony --reporter spec test )
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.