So legen Sie die Umgebungsvariable des untergeordneten Prozesses in Makefile fest

134

Ich möchte dieses Makefile ändern:

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

zu:

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

Leider funktioniert der zweite nicht (der Knotenprozess wird weiterhin mit der Standardeinstellung ausgeführt NODE_ENV.

Was habe ich verpasst?

Bodokaiser
quelle

Antworten:

153

Make-Variablen werden standardmäßig nicht in die Umgebung von Prozessen exportiert. Sie können jedoch make verwenden export, um sie dazu zu zwingen. Veränderung:

test: NODE_ENV = test

dazu:

test: export NODE_ENV = test

(vorausgesetzt, Sie haben eine ausreichend moderne Version von GNU make> = 3.77).

Verrückter Wissenschaftler
quelle
3
Ich habe GNU machen 3.81 und all: <\n\t>export PROJ_ROOT=$(CURDIR)<\n\t>echo $(PROJ_ROOT)<\n>gibt die richtige Erweiterung für die erste Zeile aus, aber nur echofür die zweite. PROJ_ROOTwird nach dem Ausführen von make nicht gesetzt. Leerzeichen =geben "ungültiger Variablenname" für den Export. Wenn die erste Zeile so vorausgesetzt ist wie in Ihrem Beispiel, wird "Befehle beginnen vor dem ersten Ziel"
angezeigt
8
@ Gauthier ja natürlich. Das habe ich nicht geschrieben. Sie haben nach dem ein <\ n \ t> hinzugefügt all:, was in meinem Beispiel nicht der Fall ist. Mein Beispiel soll wie geschrieben verwendet werden: Es definiert eine zielspezifische Variable und fügt dem Rezept KEINEN Befehl hinzu. Außerdem können Sie nicht gleichzeitig ein Rezept und eine zielspezifische Variable für ein Ziel verwenden: Sie müssen das Ziel zweimal schreiben. Sehen Sie sich das zweite Beispiel in der Frage an und stellen Sie eine neue Frage, wenn dies nicht zur Erklärung beiträgt: In Kommentaren ist nicht genügend Speicherplatz oder Formatierung vorhanden.
MadScientist
1
Was ist mit mehreren Variablen?
Holms
1
Das ist in Ordnung, aber Sie haben es dem Kopf des Ziels hinzugefügt. Nur sie im Kontext des Ziels aufzulisten, wird nicht funktionieren? Weil es bei mir nicht funktioniert
holms
2
Zielspezifische Variablen wurden in GNU make 3.77 hinzugefügt. Sie sind ab GNU make 3.81 exportierbar. Siehe git.savannah.gnu.org/cgit/make.git/tree/NEWS
MadScientist
79

Wie MadScientist betonte, können Sie einzelne Variablen exportieren mit:

export MY_VAR = foo  # Available for all targets

Oder exportieren Sie Variablen für ein bestimmtes Ziel ( zielspezifische Variablen ):

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

Sie können das .EXPORT_ALL_VARIABLESZiel auch angeben, um - Sie haben es erraten! - ALLE DINGE ZU EXPORTIEREN !!!:

.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

Siehe .EXPORT_ALL_VARIABLES

Shammel Lee
quelle
2
Seltsamerweise habe ich es früher getestet, was gezeigt hat, dass es funktioniert. (Ich weiß nicht warum jetzt.) Ich kann zurückgehen und den Kommentar löschen, denke ich.
AnthonyC
3
@AnthonyC Es funktioniert, weil es zwei MY_VARs gibt: eine ist Makefile-Variable, auf die zugegriffen wird, ${MY_VAR}und eine andere ist Bash-exportierte Variable, auf die zugegriffen wird als$$MY_VAR
Sergei
Nützlich. Es kann jedoch keine Möglichkeit gefunden werden, nur eine Reihe von Variablen zu exportieren.
Eric Chen
15

Ich brauchte die Umgebungsvariablen nur lokal, um meinen Testbefehl aufzurufen. Hier ist ein Beispiel, in dem mehrere Umgebungsvariablen in einer Bash-Shell festgelegt und der Dollar-Anmeldung entgangen werden make.

SHELL := /bin/bash

.PHONY: test tests
test tests:
    PATH=./node_modules/.bin/:$$PATH \
    JSCOVERAGE=1 \
    nodeunit tests/
ThorSummoner
quelle
6
Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung zu erhalten. Nur-Code-Antworten tragen sehr wenig dazu bei, zukünftige SO-Leser zu schulen. Ihre Antwort befindet sich in der Moderationswarteschlange, da sie von geringer Qualität ist.
Mickmackusa
ThorSummoner, diese Lösung ist nicht so flexibel wie der obige Ansatz. Beispielsweise möchte man möglicherweise eine einzige Regel zum Aufrufen eines Befehls und dann mehrere andere Regeln, die dieses Verhalten durch Festlegen von Umgebungsvariablen ändern. Bedenken Sie: test: cmd perf: export PERF = "yes" perf: test Wenn 'cmd' kompliziert ist (und normalerweise ist), ist dieser Ansatz viel einfacher zu pflegen. Ihr Ansatz zum Festlegen der Umgebungsvariablen in der cmd-Regel erschwert dies.
Keith Hanlan
1

Ich würde den ursprünglichen Zieltest neu schreiben und darauf achten, dass die erforderliche Variable IM GLEICHEN UNTERPROZESS als die zu startende Anwendung definiert ist:

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