在 makefile 中有更好的方式从脚本中获取设置环境变量的方法吗?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
在 makefile 中有更好的方式从脚本中获取设置环境变量的方法吗?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
Makefile默认的shell是/bin/sh
,它不支持source
命令。
将shell更改为/bin/bash
可以实现:
# Makefile
SHELL := /bin/bash
rule:
source env.sh && YourCommand
SHELL
为你自己的包装器来完成这个任务。在这里展示 https://gist.github.com/ingydotnet/99f7e259319f6b90e50a754f3053be7f - ingydotnet. env.sh
来完成这个任务。 - MKesper回答问题:如问,你无法。
基本问题在于,子进程无法更改父进程的环境。当进行“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
详细内容留作练习。
source compilationEnv.sh; $(CC) -c -o $< $^
或类似的命令行将作为操作行起作用。 - dmckee --- ex-moderator kitteninclude .env
(或任何键值文件)使变量在整个 Makefile 中可访问,然后仅将所需变量传递到相应的配方中。 - rypel如果你的目标只是为了在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
使用GNU Make 3.81,我可以通过以下方式从make中调用一个shell脚本:
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
将不起作用。每行都在自己的子shell中运行。
source
和命令在同一行上变得必要。使用3.81,我可以使用不同的行。为了可移植性,一行代码适用于这些版本。如果一行太长,调用外部脚本会更易读! - Eric Platon\\
结尾来表示每一行的结束。 - user5359531env.sh
替换为要源的文件的名称。它通过在bash中引用该文件并将修改后的环境格式化输出到名为makeenv
的文件中,然后由makefile进行源操作。IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
#ifdef _intel64onosx
<br/>
GCC=/opt/intel/bin/icc
<br/>
CFLAGS= -m64 -g -std=c99
<br/>
IGNORE :=$(shell bash -c "source /opt/intel/bin/iccvars.sh intel64; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
<br/>
include makeenv
- revherenv.sh
文件中的变量值包含特殊的 Make 字符,例如 #
或 $
,那么当您执行 include makeenv
时,这些值将会混乱不堪。 - donhector在shell
和GNU Make
中,有些结构是相同的。
var=1234
text="Some text"
name=value
类型。. ./vars.sh
[Makefile]
include vars.sh
那么shell脚本和Makefile可以共享相同的信息源。我找到这个问题是因为我正在寻找一个通用语法清单,可用于GNU Make和shell脚本(不关心使用哪种shell)。
编辑: Shell和make都理解${var}。这意味着您可以连接等操作。 var="一个字符串" var=${var} "第二个字符串"
shell
variables and make
variables are not always transparently interchangeable. When you include
them in your Makefile
, they must comply with make
syntax, which imposes certain characters to be escaped. For example a shell variable value like SECRET='12#34$56'
in your .vars.sh
will cause you trouble when go use it after include vars.sh
- donhector我非常喜欢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未定义的情况下重复每个规则的名称。
如果你想将变量传递给子进程,使它们成为环境变量,那么可以使用bash的set -a
和set +a
。前者的意思是,“当我设置一个变量时,也同时设置相应的环境变量。”所以这对我很有效:
check:
bash -c "set -a && source .env.test && set +a && cargo test"
这将把.env.test
中的所有内容作为环境变量传递给cargo test
。
请注意,这将允许您将环境传递给子命令,但它不会让您设置Makefile变量(它们是不同的东西)。如果您需要后者,请尝试这里的其他建议。
bash
,对于例如tcsh
的语法,$@
的语法不同)sourceThenExec.sh
的脚本,如下所示:#!/bin/bash
source whatever.sh
$@
然后,在您的makefile中,在您的目标之前加上bash sourceThenExec.sh
,例如:
ExampleTarget:
bash sourceThenExec.sh gcc ExampleTarget.C
STE=bash sourceThenExec.sh
的内容,并缩短以下内容:ExampleTarget:
$(STE) gcc ExampleTarget.C
sourceThenExec.sh
打开了一个子shell,但是命令在同一个子shell中运行。根据您的Make版本和封闭shell,您可以通过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!