Есть ли лучший способ получить скрипт, который устанавливает env vars, из make-файла?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
Есть ли лучший способ получить скрипт, который устанавливает env vars, из make-файла?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
Чтобы ответить на заданный вопрос: вы не можете.
Основная проблема заключается в том, что дочерний процесс не может изменить родительскую среду. Оболочка обходит это, не разветвляя новый процесс при source
, а просто запуская эти команды в текущем воплощении оболочки. Это прекрасно работает, но make
не является /bin/sh
(или любой другой оболочкой, для которой предназначен ваш скрипт) и не понимает этот язык (за исключением тех частей, которые у них есть общего).
Крис Додд и Фу Ба рассмотрели один возможный обходной путь, поэтому я предлагаю другой (при условии, что вы используете GNU make): постобработайте сценарий оболочки в текст, совместимый с make, и включите результат:
shell-variable-setter.make: shell-varaible-setter.sh
postprocess.py @^
# ...
else
include shell-variable-setter.make
endif
беспорядочные детали оставлены в качестве упражнения.
source compilationEnv.sh; $(CC) -c -o $< $^
или подобное будет работать как линия действия.
- person dmckee --- ex-moderator kitten; 04.04.2019
include .env
(или любой файл ключ-значение), чтобы сделать переменные доступными для всего Makefile, а затем передать только необходимые в соответствующий рецепт.
- person rypel; 24.08.2019
Оболочкой Makefile по умолчанию является /bin/sh
, которая не реализует source
.
Изменение оболочки на /bin/bash
позволяет:
# Makefile
SHELL := /bin/bash
rule:
source env.sh && YourCommand
make
, а не только для использования в строках действий. Это то, как сделать последнее, но нет прямого способа сделать первое.
- person dmckee --- ex-moderator kitten; 10.04.2019
SHELL
в свою собственную оболочку. Здесь показано gist.github.com/ingydotnet/99f7e259319f6b90e50a754f3053be7f
- person ingydotnet; 24.09.2019
Если ваша цель состоит в том, чтобы просто установить переменные среды для Make, почему бы не сохранить синтаксис Makefile и не использовать команду include
?
include other_makefile
Если вам нужно вызвать сценарий оболочки, зафиксируйте результат в команде shell
:
JUST_DO_IT=$(shell source_script)
команда оболочки должна выполняться перед целями. Однако это не установит переменные среды.
Если вы хотите установить переменные среды в сборке, напишите отдельный сценарий оболочки, который получает ваши переменные среды и вызывает make. Затем в make-файле пусть цели вызывают новый сценарий оболочки.
Например, если ваш исходный make-файл имеет цель a
, вы хотите сделать что-то вроде этого:
# mysetenv.sh
#!/bin/bash
. <script to source>
export FLAG=1
make "$@"
# Makefile
ifeq($(FLAG),0)
export FLAG=1
a:
./mysetenv.sh a
else
a:
.. do it
endif
Используя GNU Make 3.81, я могу получить сценарий оболочки из make, используя:
rule:
<tab>source source_script.sh && build_files.sh
build_files.sh «получает» переменные среды, экспортированные source_script.sh.
Обратите внимание, что с помощью:
rule:
<tab>source source_script.sh
<tab>build_files.sh
не будет работать. Каждая строка запускается в своей собственной подоболочке.
source
и команд в одной строке становится необходимым с GNU Make 4.1 (и, возможно, 4.0 тоже). Используя 3.81, я могу использовать разные строки. Для переносимости в этих версиях работает одна строка. Однако вызов внешнего скрипта более удобочитаем, если строка становится слишком длинной!
- person Eric Platon; 12.02.2018
Это работает для меня. Замените env.sh
именем файла, который вы хотите использовать. Он работает, загружая файл в bash и выводя измененную среду после ее форматирования в файл с именем makeenv
, который затем извлекается из makefile.
IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
env.sh
содержат специальные символы Make, такие как #
или $
. Когда вы сделаете include makeenv
, эти значения будут перепутаны.
- person donhector; 07.02.2020
Некоторые конструкции одинаковы в shell
и GNU Make
.
var=1234
text="Some text"
Вы можете изменить свой сценарий оболочки, чтобы получить определения. Все они должны быть простыми name=value
типами.
Ie,
[скрипт.ш]
. ./vars.sh
[Макетфайл]
include vars.sh
Тогда сценарий оболочки и Makefile могут использовать один и тот же «источник» информации. Я нашел этот вопрос, потому что искал манифест общего синтаксиса, который можно использовать в Gnu Make и сценариях оболочки (мне все равно, какая оболочка).
Изменить: Оболочки и понять ${var}. Это означает, что вы можете конкатенировать и т.д., var="Одна строка" var=${var} "Вторая строка"
shell
и переменные make
не всегда прозрачно взаимозаменяемы. Когда вы include
их в своем Makefile
, они должны соответствовать синтаксису make
, который требует экранирования определенных символов. Например, значение переменной оболочки, такое как SECRET='12#34$56'
в вашем .vars.sh
, вызовет у вас проблемы, когда вы будете использовать его после include vars.sh
.
- person donhector; 07.02.2020
Мне очень нравится ответ Фу Ба, где make вызывает скрипт, а скрипт перезванивает, чтобы сделать. Чтобы расширить этот ответ, я сделал это:
# Makefile
.DEFAULT_GOAL := all
ifndef SOME_DIR
%:
<tab>. ./setenv.sh $(MAKE) $@
else
all:
<tab>...
clean:
<tab>...
endif
--
# setenv.sh
export SOME_DIR=$PWD/path/to/some/dir
if [ -n "$1" ]; then
# The first argument is set, call back into make.
$1 $2
fi
Это имеет дополнительное преимущество использования $(MAKE) в случае, если кто-то использует уникальную программу make, а также будет обрабатывать любое правило, указанное в командной строке, без необходимости дублировать имя каждого правила в случае, когда SOME_DIR не определен. .
Мое решение: (при условии, что у вас есть bash
, синтаксис для $@
отличается, например, для tcsh
)
Имейте скрипт sourceThenExec.sh
как таковой:
#!/bin/bash
source whatever.sh
$@
Затем в вашем make-файле перед вашими целями ставится bash sourceThenExec.sh
, например:
ExampleTarget:
bash sourceThenExec.sh gcc ExampleTarget.C
Конечно, вы можете поместить что-то вроде STE=bash sourceThenExec.sh
в начало вашего make-файла и сократить это:
ExampleTarget:
$(STE) gcc ExampleTarget.C
Все это работает, потому что sourceThenExec.sh
открывает подоболочку, но затем команды выполняются в той же подоболочке.
Недостатком этого метода является то, что файл создается для каждой цели, что может быть нежелательно.
Если вы хотите поместить переменные в окружение, чтобы они передавались дочерним процессам, вы можете использовать bash set -a
и set +a
. Первое означает: «Когда я устанавливаю переменную, устанавливаю и соответствующую переменную среды». Так что это работает для меня:
check:
bash -c "set -a && source .env.test && set +a && cargo test"
Это передаст все в .env.test
в cargo test
как переменные среды.
Обратите внимание, что это позволит вам передать среду подкомандам, но не позволит вам установить переменные Makefile (которые в любом случае разные вещи). Если вам нужно последнее, вы должны попробовать одно из других предложений здесь.
Если вам нужно только несколько известных переменных, экспорт в makefile может быть опцией, вот пример того, что я использую.
$ grep ID /etc/os-release
ID=ubuntu
ID_LIKE=debian
$ cat Makefile
default: help rule/setup/lsb
source?=.
help:
-${MAKE} --version | head -n1
rule/setup/%:
echo ID=${@F}
rule/setup/lsb: /etc/os-release
${source} $< && export ID && ${MAKE} rule/setup/$${ID}
$ make
make --version | head -n1
GNU Make 3.81
. /etc/os-release && export ID && make rule/setup/${ID}
make[1]: Entering directory `/tmp'
echo ID=ubuntu
ID=ubuntu
-- http://rzr.online.fr/q/gnumake
В зависимости от вашей версии Make и прилагаемой оболочки вы можете реализовать хорошее решение с помощью eval
, cat
и цепочек вызовов с &&
:
ENVFILE=envfile
source-via-eval:
@echo "FOO: $${FOO}"
@echo "FOO=AMAZING!" > $(ENVFILE)
@eval `cat $(ENVFILE)` && echo "FOO: $${FOO}"
И быстрый тест:
> make source-via-eval
FOO:
FOO: AMAZING!
Элегантное решение найдено здесь:
ifneq (,$(wildcard ./.env))
include .env
export
endif
Другой возможный способ — создать скрипт sh, например run.sh
, найти необходимые скрипты и вызвать make внутри скрипта.
#!/bin/sh
source script1
source script2 and so on
make
target: output_source
bash ShellScript_name.sh
попробуйте это, это сработает, скрипт находится внутри текущего каталога.