如何在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.shreplace你想要的文件的名字。 它通过在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 

一些构造在shellGNU Make

 var=1234 text="Some text" 

你可以改变你的shell脚本来定义这个定义。 它们都必须是简单的name=valuetypes。

也就是说,

[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 

http://rzr.online.fr/q/gnumake

如果你想让variables进入环境 ,所以它们被传递给subprocess,那么你可以使用bash的set -aset +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 

试试这个会起作用,脚本在当前目录里面。