Есть ли лучший способ для источника script, который устанавливает env vars изнутри файла makefile?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) [email protected]'
else
...targets...
endif
Есть ли лучший способ для источника script, который устанавливает env vars изнутри файла makefile?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) [email protected]'
else
...targets...
endif
Чтобы ответить на заданный вопрос: вы не можете.
Основная проблема заключается в том, что дочерний процесс не может изменить родительскую среду. Оболочка обходит это, не открывая новый процесс, когда source
'ing, но просто запускает эти команды в текущем воплощении оболочки. Это работает отлично, но make
не /bin/sh
(или какая-либо оболочка для вашего script) и не понимает этот язык (кроме битов, которые у них есть).
Chris Dodd и Foo Bah обратились к одному из возможных способов обхода, поэтому я предлагаю другое (если вы используете GNU make): выполните обработку оболочки script, чтобы создать совместимый текст и включить результат:
shell-variable-setter.make: shell-varaible-setter.sh
postprocess.py @^
# ...
else
include shell-variable-setter.make
endif
беспорядочные детали, оставленные как упражнение.
Если ваша цель - просто установить переменные среды для Make, почему бы не сохранить их в синтаксисе Makefile и использовать команду include
?
include other_makefile
Если вам нужно вызвать оболочку script, запишите результат в команду shell
:
JUST_DO_IT=$(shell source_script)
команда оболочки должна запускаться перед целями. Однако это не изменит переменные среды.
Если вы хотите установить переменные среды в сборке, напишите отдельную оболочку script, которая будет вызывать переменные среды и вызовы make. Затем в make файле нужно, чтобы цели вызывали новую оболочку script.
Например, если ваш исходный make файл имеет цель a
, то вы хотите сделать что-то вроде этого:
# mysetenv.sh
#!/bin/bash
. <script to source>
export FLAG=1
make "[email protected]"
# Makefile
ifeq($(FLAG),0)
export FLAG=1
a:
./mysetenv.sh a
else
a:
.. do it
endif
Использование GNU Make 3.81 Я могу создать оболочку script из make using:
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
не будет работать. Каждая строка запускается в своей подоболочке.
Это работает для меня. Замените env.sh
именем файла, который вы хотите использовать. Он работает путем поиска файла в bash и вывода измененной среды после ее форматирования в файл с именем makeenv
, который затем получает файл makefile.
IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
Makefile default shell /bin/sh
, который не реализует source
.
Изменение оболочки на /bin/bash
позволяет:
# Makefile
SHELL := /bin/bash
rule:
source env.sh && YourCommand
Некоторые конструкции одинаковы в shell
и в GNU Make
.
var=1234
text="Some text"
Вы можете изменить оболочку script, чтобы указать параметры. Все они должны быть простыми типами name=value
.
Т.е.,
[script.sh]
. ./vars.sh
[Make файл]
include vars.sh
Тогда оболочка script и Makefile могут совместно использовать один и тот же "источник" информации. Я нашел этот вопрос, потому что я искал манифест общего синтаксиса, который можно использовать в скриптах Gnu Make и shell (мне все равно, какая оболочка).
Изменить: оболочки и понять ${var}. Это означает, что вы можете конкатенировать и т.д. var = "Одна строка" var = ${var} "Вторая строка"
Мне очень нравится Foo Bah ответ, где вызывают вызовы script, а script - назад. Чтобы расширить этот ответ, я сделал следующее:
# Makefile
.DEFAULT_GOAL := all
ifndef SOME_DIR
%:
<tab>. ./setenv.sh $(MAKE) [email protected]
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
, синтаксис для [email protected]
для tcsh
отличается)
Имейте script sourceThenExec.sh
, как таковой:
#!/bin/bash
source whatever.sh
[email protected]
Затем в вашем make файле предисловие к вашим целям с помощью bash sourceThenExec.sh
, например:
ExampleTarget:
bash sourceThenExec.sh gcc ExampleTarget.C
Вы можете, конечно, добавить что-то вроде STE=bash sourceThenExec.sh
в начало своего файла makefile и сократить это:
ExampleTarget:
$(STE) gcc ExampleTarget.C
Все это работает, потому что sourceThenExec.sh
открывает подоболочку, но тогда команды выполняются в одной и той же подоболочке.
Недостатком этого метода является то, что файл получает источник для каждой цели, что может быть нежелательным.
Другим возможным способом было бы создание sh script, например run.sh
, источник необходимых скриптов и вызов make внутри script.
#!/bin/sh
source script1
source script2 and so on
make
Если вам нужна только несколько известных переменных, экспортирующих в make файл, это вариант, вот пример того, что я использую.
$ 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
Если вы хотите получить переменные в среде, чтобы они передавались дочерним процессам, вы можете использовать bash set -a
и set +a
. Первое означает: "Когда я устанавливаю переменную, задайте также соответствующую переменную среды". Так это работает для меня:
check:
bash -c "set -a && source .env.test && set +a && cargo test"
Это будет передавать все в .env.test
на cargo test
в качестве переменных среды.
Обратите внимание, что это позволит вам передать среду в под-команды, но это не позволит вам устанавливать переменные Makefile (которые все равно разные). Если вам нужно последнее, вы должны попробовать одно из других предложений здесь.
target: output_source
bash ShellScript_name.sh
попробуйте, он будет работать, script находится внутри текущего каталога.