Shell 如何在Makefile中生成脚本?
是否有更好的方法从makefile中获取设置环境变量的脚本Shell 如何在Makefile中生成脚本?,shell,makefile,Shell,Makefile,是否有更好的方法从makefile中获取设置环境变量的脚本 FLAG ?= 0 ifeq ($(FLAG),0) export FLAG=1 /bin/myshell -c '<source scripts here> ; $(MAKE) $@' else ...targets... endif 标志?=0 ifeq($(标志),0) 导出标志=1 /bin/myshell-c'$(MAKE)$@' 其他的 ……目标。。。 恩迪夫 如果您的目标只是为Make设置环境变量,为什么不将
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
标志?=0
ifeq($(标志),0)
导出标志=1
/bin/myshell-c'$(MAKE)$@'
其他的
……目标。。。
恩迪夫
如果您的目标只是为Make设置环境变量,为什么不将其保留为Makefile语法并使用include
命令
include other_makefile
如果必须调用shell脚本,请在shell
命令中捕获结果:
JUST_DO_IT=$(shell source_script)
shell命令应在目标之前运行。但是,这不会设置环境变量
如果要在生成中设置环境变量,请编写一个单独的shell脚本,以获取环境变量和调用。然后,在makefile中,让目标调用新的shell脚本
例如,如果原始makefile具有targeta
,则需要执行以下操作:
# 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
#mysetenv.sh
#!/bin/bash
.
导出标志=1
使“$@”
#生成文件
ifeq($(标志),0)
导出标志=1
a:
./mysetenv.sh a
其他的
a:
.. 做吧
恩迪夫
回答问题:你不能
基本问题是子进程不能改变父进程的环境。shell通过在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
凌乱的细节留作练习。在
shell
和gnumake
中,有些构造是相同的
var=1234
text="Some text"
您可以修改shell脚本来定义源代码。它们都必须是简单的name=value
类型
即
[script.sh]
. ./vars.sh
[制作文件]
include vars.sh
然后,shell脚本和Makefile可以共享相同的信息“源”。我发现这个问题是因为我在寻找可以在GNUmake和shell脚本中使用的公共语法清单(我不关心哪个shell)
编辑:shell并使其理解${var}。这意味着您可以连接,等等,
var=“一个字符串”
var=${var}“第二个字符串”这对我很有用。用要源文件的名称替换
env.sh
。它的工作原理是在bash中对文件进行源化,并在格式化后将修改后的环境输出到名为makeenv
的文件中,然后由makefile进行源化
IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
使用GNU Make 3.81,我可以使用以下方法从Make获取shell脚本:
rule:
<tab>source source_script.sh && build_files.sh
规则:
source\u script.sh和build\u files.sh
build_files.sh“获取”由source_script.sh导出的环境变量
请注意,使用:
rule:
<tab>source source_script.sh
<tab>build_files.sh
规则:
source_script.sh
build_files.sh
这是行不通的。每一行都在它自己的子shell中运行。如果您只需要在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
$grep ID/etc/os发行版
ID=ubuntu
ID_LIKE=debian
$cat生成文件
默认值:帮助规则/设置/lsb
来源?=。
帮助:
-${MAKE}--version|head-n1
规则/设置/%:
echo ID=${@F}
规则/设置/lsb:/etc/os发布
${source}$<&&export-ID&&${MAKE}规则/setup/$${ID}
$make
make——版本|头部-n1
GNU Make 3.81
. /etc/os发行版和导出ID和制定规则/setup/${ID}
make[1]:输入目录“/tmp”
echo ID=ubuntu
ID=ubuntu
--
我的解决方案:(假设您有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中运行
这种方法的缺点是为每个目标获取文件源,这可能是不可取的。我非常喜欢Foo-Bah的回答,make调用脚本,脚本调用make。为了进一步说明这个答案,我做了以下工作:
# Makefile
.DEFAULT_GOAL := all
ifndef SOME_DIR
%:
<tab>. ./setenv.sh $(MAKE) $@
else
all:
<tab>...
clean:
<tab>...
endif
如果有人正在使用唯一的MAKE程序,则使用$(MAKE)还有一个额外的优点,并且还将处理命令行上指定的任何规则,而不必在未定义某个目录的情况下复制每个规则的名称。另一种可能的方法是创建sh脚本,例如run.sh
,获取所需脚本的源代码,并在脚本内部调用make
#!/bin/sh
source script1
source script2 and so on
make
如果希望将变量放入环境中,以便将它们传递给子进程,那么可以使用bash的set-a
和set+a
。前者的意思是,“当我设置一个变量时,也要设置相应的环境变量。”所以这对我来说是可行的:
check:
bash -c "set -a && source .env.test && set +a && cargo test"
这将把.env.test
中的所有内容作为环境变量传递给货物测试
请注意,这将允许您将环境传递给子命令,但不允许您设置Makefile变量(无论如何,它们是不同的)。如果您需要后者,您应该在这里尝试其他建议。Makefile默认shell是/bin/sh
,它不实现源代码
将shell更改为/bin/bash
可以:
# Makefile
SHELL := /bin/bash
rule:
source env.sh && YourCommand
试试这个,它会工作的,脚本在当前目录中。根据Make和封闭shell的版本,您可以通过eval
,cat
,以及使用链接调用来实现一个很好的解决方案
# Makefile
SHELL := /bin/bash
rule:
source env.sh && YourCommand
target: output_source
bash ShellScript_name.sh
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!
ifneq (,$(wildcard ./.env))
include .env
export
endif