Как установить переменную среды дочернего процесса в Makefile


135

Я хотел бы изменить этот 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

чтобы:

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

К сожалению, второй не работает (процесс узла по-прежнему работает со значением по умолчанию NODE_ENV.

Что я пропустил?


Ваш Unfortunatelyкомментарий связан с недоразумением между переменной среды и Makefileпеременной. Лучший способ доказать, что переменная среды установлена, - это запросить эту переменную среды внутри другой программы, которая будет makeвызывать. Только действие echo $(BLAH)- это просто оценка механизма ключа / значения Makefile внутри Makefile. В python вы можете print(os.getenv("MURDOC")) действительно запросить переменную среды.
— truthadjustr

Ответы:


154

По умолчанию переменные make не экспортируются в среду процессов make invokes ... Однако вы можете использовать make, exportчтобы заставить их сделать это. Изменить:

test: NODE_ENV = test

к этому:

test: export NODE_ENV = test

(при условии, что у вас достаточно современная версия GNU make> = 3.77).


3
У меня GNU make 3.81 all: <\n\t>export PROJ_ROOT=$(CURDIR)<\n\t>echo $(PROJ_ROOT)<\n>выводит правильное расширение для первой строки, но только echoдля второй. PROJ_ROOTне устанавливается после запуска make. Пробелы вокруг =дают "неправильное имя переменной" для экспорта. Наличие первой строки в качестве предварительного условия, как в вашем примере, дает «команды начинаются до первой цели»
— Готье

8
@Gauthier да, конечно. Я не об этом писал. Вы добавили <\ n \ t> после all:, чего нет в моем примере. Мой пример предназначен для использования в том виде, в каком он написан: он определяет переменную, специфичную для цели, а НЕ добавляет команду в рецепт. Также вы не можете использовать рецепт и переменную, зависящую от цели, на цели одновременно: вы должны написать цель дважды. См. Второй пример в вопросе и задайте новый вопрос, если это не помогает объяснить: в комментариях недостаточно места или форматирования.
— MadScientist

1
А как насчет нескольких переменных?
— Холмс

1
Это нормально, но вы добавили его в заголовок цели. Просто перечислить их в контексте цели не получится? Потому что у меня это не работает,
— Холмс

2
Переменные для конкретных целей были добавлены в GNU make 3.77. Их можно экспортировать, начиная с версии GNU make 3.81. См. Git.savannah.gnu.org/cgit/make.git/tree/NEWS
— MadScientist

80

Как указал MadScientist , вы можете экспортировать отдельные переменные с помощью:

export MY_VAR = foo  # Available for all targets

Или экспортировать переменные для конкретной цели ( целевой конкретные переменные ):

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

Вы также можете указать .EXPORT_ALL_VARIABLESцель - как вы уже догадались! - ЭКСПОРТИРОВАТЬ ВСЕ ВСЕ !!!:

.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

см. .EXPORT_ALL_VARIABLES


2
Как ни странно, я проверил это раньше, и это показало, что он работает ... (не знаю, почему сейчас ..) Я могу вернуться и удалить комментарий, я думаю ...
— AnthonyC

3
@AnthonyC Это работает, потому что есть два MY_VARs: один - это переменная makefile, доступ к которой осуществляется как, ${MY_VAR}а другой - переменная, экспортируемая из bash, доступная как$$MY_VAR
— Сергей

Полезно. Но не могу найти способ экспортировать только набор переменных.
— Эрик Чен

14

Мне нужны были только переменные среды локально, чтобы вызвать мою тестовую команду, вот пример, устанавливающий несколько переменных среды в оболочке bash и избегающий входа в систему make.

SHELL := /bin/bash

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

6
Измените свой ответ, включив в него некоторые пояснения. Ответы только на коде мало что могут сделать для обучения будущих читателей SO. Ваш ответ находится в очереди на модерацию как некачественный.
— mickmackusa

ThorSummoner, это решение не так гибко, как вышеприведенный подход. Например, кто-то может пожелать иметь одно правило для вызова команды, а затем несколько других правил, которые изменяют это поведение, устанавливая переменные среды. Рассмотрим: test: cmd perf: export PERF = "yes" perf: test Если cmd сложен (а это обычно бывает), то этот подход намного проще поддерживать. Ваш подход к установке переменной среды в правиле cmd усложняет эту задачу.
— Keith

1

Я бы переписал исходный целевой тест, позаботившись о том, чтобы нужная переменная была определена В ЖЕ ПОДПРОЦЕССЕ как запускаемое приложение:

test:
    ( NODE_ENV=test mocha --harmony --reporter spec test )
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.