是否有更好的方法从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
Answers:
要回答询问的问题:您不能。
基本问题是子进程不能更改父进程的环境。外壳由能够规避这种不分叉一个新的进程时,source
荷兰国际集团“,但只是运行在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 $< $^
或类似名称将用作操作线。
include .env
(或任何键值文件)使整个Makefile都可以访问变量,然后仅将所需的变量传递到相应的配方中。
Makefile的默认外壳程序/bin/sh
未实现source
。
更改外壳/bin/bash
使其成为可能:
# Makefile
SHELL := /bin/bash
rule:
source env.sh && YourCommand
make
而不仅仅是在操作行中使用。这是做后者的方法,但是没有直接方法做前者。
SHELL
自己的包装器来完成此操作。此处显示的gist.github.com/ingydotnet/99f7e259319f6b90e50a754f3053be7f
如果您的目标只是为Make设置环境变量,为什么不将其保留在Makefile语法中并使用include
命令?
include other_makefile
如果必须调用shell脚本,请通过以下shell
命令捕获结果:
JUST_DO_IT=$(shell source_script)
shell命令应在目标之前运行。但是,这不会设置环境变量。
如果要在构建中设置环境变量,请编写一个单独的Shell脚本来获取环境变量并调用make。然后,在makefile中,让目标调用新的shell脚本。
例如,如果您的原始makefile具有target 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
不管用。每行都在其自己的子外壳中运行。
source
对于GNU Make 4.1(也许还有4.0),必须将和命令保持在同一行。使用3.81,我可以使用不同的行。为了便于移植,这些版本之间只有一行兼容。但是,如果行太长,则调用外部脚本更具可读性!
这对我有用。env.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
IGNORE :=$(shell bash -c "source /opt/intel/bin/iccvars.sh intel64; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
make
。
env.sh
包含特殊制作字符,如#
或$
。当您执行include makeenv
这些操作时,这些值将全部弄乱。
有些结构是在同shell
和GNU Make
。
var=1234
text="Some text"
您可以更改您的Shell脚本来获取定义。它们必须都是简单name=value
类型。
即
[script.sh]
. ./vars.sh
[Makefile]
include vars.sh
然后,shell脚本和Makefile可以共享相同的信息“源”。我找到了这个问题,因为我正在寻找可以在Gnu Make和shell脚本中使用的通用语法的清单(我不在乎哪个shell)。
编辑: 外壳并理解$ {var}。这意味着您可以串联等,var =“一个字符串” var = $ {var}“第二个字符串”
shell
变量和make
变量并非始终透明地互换。当您在中使用include
它们时Makefile
,它们必须遵守make
语法,该语法强加了要转义的某些字符。例如SECRET='12#34$56'
,您中的shell变量值在.vars.sh
之后使用时会给您带来麻烦include vars.sh
我真的很喜欢Foo Bah的回答,在该命令中make调用了脚本,而脚本又回调了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
$@
然后,在您的makefile中,使用以下命令作为目标的开头 bash sourceThenExec.sh
,例如:
ExampleTarget:
bash sourceThenExec.sh gcc ExampleTarget.C
你当然可以放一些 STE=bash sourceThenExec.sh
在makefile的顶部并缩短它:
ExampleTarget:
$(STE) gcc ExampleTarget.C
所有这些都有效,因为sourceThenExec.sh
打开了一个子外壳,但是命令在同一子外壳中运行。
这种方法的缺点是为每个目标获取文件,这可能是不希望的。
如果仅需要几个已知变量,可以在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