是否有更好的方法从makefile中获取设置env变量的脚本?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
答案 0 :(得分:53)
Makefile默认shell为source
,但未实现/bin/bash
。
将shell更改为# Makefile
SHELL := /bin/bash
rule:
source env.sh && YourCommand
使其成为可能:
let odd = 0;
for (let i = 0; i < 1000000000; i++) {
if (i % 2) odd++;
}
odd;
答案 1 :(得分:39)
要回答问题:你不能。
基本问题是子进程无法改变父进程的环境。 shell {em>>在source
时没有分支新进程,而只是在shell的当前版本中运行这些命令时,shell会解决这个问题。这工作正常,但make
不是/bin/sh
(或者你的脚本所用的任何shell)并且不理解那种语言(除了它们共有的位)。
Chris Dodd和Foo Bah解决了一个可能的解决方法,所以我建议另一个(假设你正在运行GNU make):将shell脚本后处理为make兼容文本并包含结果:
shell-variable-setter.make: shell-varaible-setter.sh
postprocess.py @^
# ...
else
include shell-variable-setter.make
endif
凌乱的细节留作练习。
答案 2 :(得分:21)
如果您的目标只是为Make设置环境变量,为什么不将它保留在Makefile语法中并使用include
命令?
include other_makefile
如果必须调用shell脚本,请在shell
命令中捕获结果:
JUST_DO_IT=$(shell source_script)
shell命令应该在目标之前运行。但是,这不会设置环境变量。
如果要在构建中设置环境变量,请编写一个单独的shell脚本来源环境变量并调用make。然后,在makefile中,让目标调用新的shell脚本。
例如,如果您的原始makefile具有目标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
答案 3 :(得分:16)
使用GNU Make 3.81我可以使用make来源shell脚本:
rule:
<tab>source source_script.sh && build_files.sh
build_files.sh&#34;得到&#34; source_script.sh导出的环境变量。
请注意使用:
rule:
<tab>source source_script.sh
<tab>build_files.sh
不起作用。每一行都在自己的子shell中运行。
答案 4 :(得分:10)
这对我有用。将env.sh
替换为您要提供的文件的名称。它的工作原理是在bash中获取文件并在格式化之后将修改后的环境输出到名为makeenv
的文件,然后由makefile提供。
IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
答案 5 :(得分:5)
shell
和GNU Make
中的某些结构相同。
var=1234
text="Some text"
您可以更改shell脚本以获取定义。它们必须都是简单的name=value
类型。
即,
[script.sh]
. ./vars.sh
[生成文件]
include vars.sh
然后shell脚本和Makefile可以共享相同的“信息源”。我发现了这个问题,因为我正在寻找可以在Gnu Make和shell脚本中使用的通用语法清单(我不关心哪个shell)。
编辑:轰炸并理解 $ {var} 。这意味着你可以连接等, var =“一个字符串” var = $ {var}“第二个字符串”
答案 6 :(得分:3)
我真的很喜欢Foo Bah的答案,其中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的情况下复制每个规则的名称没有定义。
答案 7 :(得分:1)
我的解决方案:(假设您拥有bash
,$@
的语法与tcsh
不同,例如)
有一个脚本sourceThenExec.sh
,如下:
#!/bin/bash
source whatever.sh
$@
然后,在您的makefile中,使用bash sourceThenExec.sh
为您的目标开头,例如:
ExampleTarget:
bash sourceThenExec.sh gcc ExampleTarget.C
您当然可以将STE=bash sourceThenExec.sh
之类的内容放在makefile的顶部并缩短它:
ExampleTarget:
$(STE) gcc ExampleTarget.C
所有这些都有效,因为sourceThenExec.sh
打开了一个子shell,但命令在同一个子shell中运行。
此方法的缺点是文件来源于每个目标,这可能是不合需要的。
答案 8 :(得分:1)
另一种可能的方法是创建一个sh脚本,例如run.sh
,获取所需的脚本并在脚本中调用make。
#!/bin/sh
source script1
source script2 and so on
make
答案 9 :(得分:0)
如果只需要一些已知的变量,可以选择在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
答案 10 :(得分:0)
如果您想将变量放入环境,以便将它们传递给子流程,那么您可以使用bash&#39; set -a
和set +a
。前者意味着,&#34;当我设置变量时,也设置相应的环境变量。&#34;所以这对我有用:
check:
bash -c "set -a && source .env.test && set +a && cargo test"
这会将.env.test
中的所有内容传递给cargo test
作为环境变量。
请注意,这将允许您将环境传递给子命令,但它不允许您设置Makefile变量(无论如何都是不同的东西)。如果你需要后者,你应该尝试其中一个建议。
答案 11 :(得分:0)
根据您的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!
答案 12 :(得分:0)
找到了here的优雅解决方案:
ifneq (,$(wildcard ./.env))
include .env
export
endif
答案 13 :(得分:-1)
target: output_source
bash ShellScript_name.sh
试试这个它会起作用,脚本在当前目录中。