Есть ли лучший способ для источника 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 находится внутри текущего каталога.