如何在Makefile中获取脚本?
有没有更好的方法来从一个生成文件中获取设置envvariables的脚本?
FLAG ?= 0 ifeq ($(FLAG),0) export FLAG=1 /bin/myshell -c '<source scripts here> ; $(MAKE) $@' else ...targets... endif
要回答这个问题: 你不能 。
基本的问题是,一个孩子的过程不能改变父母的环境。 shell通过在source
不分出新的进程来解决这个问题,而只是在shell的当前版本中运行这些命令。 这很好,但是make
不是/bin/sh
(或者脚本的任何shell),并且不理解那个语言(除了它们的共同点)。
Chris Dodd和Foo Bah提出了一种可能的解决方法,所以我会build议另外一种(假设你正在运行GNU make):将shell脚本后处理成兼容的文本并包含结果:
shell-variable-setter.make: shell-varaible-setter.sh postprocess.py @^ # ... else include shell-variable-setter.make endif
凌乱的细节留作练习。
如果你的目标是仅仅为Make设置环境variables,为什么不把它保存在Makefile语法中并使用include
命令呢?
include other_makefile
如果您必须调用shell脚本,请在shell
命令中捕获结果:
JUST_DO_IT=$(shell source_script)
shell命令应该在目标之前运行。 但是这不会设置环境variables。
如果你想在构build中设置环境variables,编写一个单独的shell脚本来源,你的环境variables和调用make。 然后,在makefile中,让target调用新的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导出的环境variables。
请注意,使用:
rule: <tab>source source_script.sh <tab>build_files.sh
不pipe用。 每行都在自己的子shell中运行。
这对我有用。 用env.sh
replace你想要的文件的名字。 它通过在bash中获取文件并将格式化后的修改后的环境输出到一个名为makeenv
的文件中,然后由makefile生成。
IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv") include makeenv
Makefile的默认shell是/bin/sh
,它没有实现source
。
将shell更改为/bin/bash
使其成为可能:
# Makefile SHELL := /bin/bash rule: source env.sh && YourCommand
一些构造在shell
和GNU Make
。
var=1234 text="Some text"
你可以改变你的shell脚本来定义这个定义。 它们都必须是简单的name=value
types。
也就是说,
[script.sh]
. ./vars.sh
[生成文件]
include vars.sh
然后,shell脚本和Makefile可以共享相同的“信息来源”。 我发现这个问题,因为我正在寻找可以在GNU Make和shell脚本中使用的通用语法清单(我不关心哪个shell)。
编辑:壳和让理解$ {var} 。 这意味着你可以连接等,var =“一个string”var = $ {var}“第二个string”
我真的很喜欢Foo Bah的回答,在那里打电话给脚本,剧本回电。 为了扩大这个答案,我做了这个:
# 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的情况下复制每个规则的名称。
我的解决scheme:(假设你有bash
, $@
的语法与tcsh
不同)
有一个脚本sourceThenExec.sh
,如:
#!/bin/bash source whatever.sh $@
然后,在你的makefile中,用bash sourceThenExec.sh
作为序言,例如:
ExampleTarget: bash sourceThenExec.sh gcc ExampleTarget.C
你当然可以在你的makefile的顶部join一些像STE=bash sourceThenExec.sh
东西,并缩短这个:
ExampleTarget: $(STE) gcc ExampleTarget.C
所有这些工作,因为sourceThenExec.sh
打开一个子shell,但然后命令运行在相同的子shell。
这种方法的缺点是文件来源于每个目标,这可能是不可取的。
另一个可能的方法是创build一个sh脚本,例如run.sh
,获取所需的脚本并在脚本中调用make。
#!/bin/sh source script1 source script2 and so on make
如果你只需要一些已知的variables导出在生成文件可以是一个选项,这里是我正在使用的一个例子。
$ 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
如果你想让variables进入环境 ,所以它们被传递给subprocess,那么你可以使用bash的set -a
和set +a
。 前者的意思是“当我设置一个variables时,也设置相应的环境variables。” 所以这对我有用:
check: bash -c "set -a && source .env.test && set +a && cargo test"
这将通过.env.test
所有内容作为环境variables进行cargo test
。
请注意,这会让你将一个环境传递给子命令,但是它不会让你设置Makefilevariables(这是不同的东西)。 如果你需要后者,你应该尝试其中的一个build议。
target: output_source bash ShellScript_name.sh
试试这个会起作用,脚本在当前目录里面。