Jak ustawić zmienną środowiskową procesu potomnego w Makefile


143

Chciałbym zmienić ten plik 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

do:

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

Niestety drugi nie działa (proces węzła nadal działa z domyślnym NODE_ENV.

Co mnie ominęło?


Twój Unfortunatelykomentarz wynika z nieporozumienia między zmienną środowiskową a Makefilezmienną. Najlepszym sposobem udowodnienia, że ​​zmienna środowiskowa została ustawiona, jest makewysłanie zapytania do tej zmiennej w innym programie, który zostanie wywołany. Jedynym działaniem echo $(BLAH)jest po prostu ocena mechanizmu klucza / wartości Makefile wewnątrz Makefile. W Pythonie możesz print(os.getenv("MURDOC")) naprawdę zapytać o zmienną środowiskową.
— eigenfield

Odpowiedzi:


159

Zmienne make nie są domyślnie eksportowane do środowiska procesów make invokes ... Możesz jednak użyć marek, exportaby je do tego zmusić. Zmiana:

test: NODE_ENV = test

do tego:

test: export NODE_ENV = test

(zakładając, że masz wystarczająco nowoczesną wersję GNU make> = 3.77).


3
Mam GNU make 3.81 i all: <\n\t>export PROJ_ROOT=$(CURDIR)<\n\t>echo $(PROJ_ROOT)<\n>wyprowadza poprawne rozszerzenie dla pierwszego wiersza, ale tylko echodla drugiego. PROJ_ROOTnie jest ustawiana po uruchomieniu make. Spacje wokół =dają „złą nazwę zmiennej” do eksportu. Pierwszy wiersz jako warunek wstępny, jak w przykładzie, daje „polecenia rozpoczynające się przed pierwszym celem”
— Gauthier

8
@Gauthier tak, oczywiście. Nie o tym napisałem. Dodałeś <\ n \ t> po znaku all:, którego nie ma w moim przykładzie. Mój przykład ma być używany tak, jak napisano: definiuje zmienną specyficzną dla celu, NIE dodaje polecenia do receptury. Nie możesz również użyć receptury i zmiennej specyficznej dla celu w tym samym czasie: musisz napisać cel dwukrotnie. Zobacz drugi przykład w pytaniu i zadaj nowe pytanie, jeśli to nie pomaga w wyjaśnieniu: nie ma wystarczającej ilości miejsca lub formatowania w komentarzach.
— MadScientist

1
A co z wieloma zmiennymi?
— holms

1
W porządku, ale dodałeś to do głowy celu. Samo wymienienie ich w kontekście celu nie zadziała? Ponieważ to nie działa dla mnie
— holms

2
Zmienne specyficzne dla celu zostały dodane w GNU make 3.77. Można je eksportować od wersji GNU 3.81. Zobacz git.savannah.gnu.org/cgit/make.git/tree/NEWS
— MadScientist

93

Jak wskazał MadScientist , możesz wyeksportować poszczególne zmienne za pomocą:

export MY_VAR = foo  # Available for all targets

Lub zmienne eksportowych dla określonej docelowej ( target-specyficzne zmienne ):

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

Możesz także określić .EXPORT_ALL_VARIABLEScel - zgadłeś! - EKSPORTUJ WSZYSTKIE RZECZY !!!:

.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

zobacz .EXPORT_ALL_VARIABLES


2
Co dziwne, przetestowałem go wcześniej i pokazałem, że działa .. (nie wiem dlaczego teraz ..) Mogę cofnąć się i usunąć komentarz chyba ..
— AnthonyC

3
@AnthonyC Działa, ponieważ istnieją dwa MY_VARs: jeden to zmienna makefile, do której dostęp jest dostępna jako, ${MY_VAR}a druga to zmienna eksportowana bash, dostępna jako$$MY_VAR
— Sergei

Przydatny. Ale nie mogę znaleźć sposobu na wyeksportowanie tylko zestawu zmiennych.
— Eric Chen

15

Potrzebowałem zmiennych środowiskowych tylko lokalnie, aby wywołać moje polecenie testowe, oto przykład ustawiania wielu zmiennych środowiskowych w powłoce bash i unikania znaku dolara make.

SHELL := /bin/bash

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

6
Zmień swoją odpowiedź, dołączając wyjaśnienie. Odpowiedzi zawierające tylko kod w niewielkim stopniu kształcą przyszłych czytelników SO. Twoja odpowiedź znajduje się w kolejce moderacji za niską jakość.
— mickmackusa

ThorSummoner, to rozwiązanie nie jest tak elastyczne, jak powyższe podejście. Na przykład, ktoś może chcieć mieć jedną regułę wywołującą polecenie, a następnie kilka innych reguł, które modyfikują to zachowanie poprzez ustawienie zmiennych środowiskowych. Zastanów się: test: cmd perf: export PERF = "yes" perf: test Jeśli 'cmd' jest skomplikowane (i zwykle jest), to takie podejście jest dużo łatwiejsze do utrzymania. Twoje podejście do ustawiania zmiennej środowiskowej w regule cmd utrudnia to.
— Keith Hanlan

2

Chciałbym ponownie napisać oryginalny test docelowy, uważając, aby potrzebna zmienna została zdefiniowana W TYM SAMYM PODPROCESIE co aplikacja do uruchomienia:

test:
    ( NODE_ENV=test mocha --harmony --reporter spec test )
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.