如何在Makefile中获取脚本?

时间:2011-09-21 23:10:02

标签: shell makefile

是否有更好的方法从makefile中获取设置env变量的脚本?

FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif

14 个答案:

答案 0 :(得分:53)

Makefile默认shell为source,但未实现/bin/bash

将shell更改为# Makefile SHELL := /bin/bash rule: source env.sh && YourCommand 使其成为可能:

let odd = 0;
for (let i = 0; i < 1000000000; i++) {
    if (i % 2) odd++;
}
odd;    

答案 1 :(得分:39)

要回答问题:你不能

基本问题是子进程无法改变父进程的环境。 shell {em>>在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

凌乱的细节留作练习。

答案 2 :(得分:21)

如果您的目标只是为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

答案 3 :(得分:16)

使用GNU Make 3.81我可以使用make来源shell脚本:

rule:
<tab>source source_script.sh && build_files.sh

build_files.sh&#34;得到&#34; source_script.sh导出的环境变量。

请注意使用:

rule:
<tab>source source_script.sh
<tab>build_files.sh

不起作用。每一行都在自己的子shell中运行。

答案 4 :(得分:10)

这对我有用。将env.sh替换为您要提供的文件的名称。它的工作原理是在bash中获取文件并在格式化之后将修改后的环境输出到名为makeenv的文件,然后由makefile提供。

IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")                         
include makeenv   

答案 5 :(得分:5)

shellGNU Make中的某些结构相同。

var=1234
text="Some text"

您可以更改shell脚本以获取定义。它们必须都是简单的name=value类型。

即,

[script.sh]

. ./vars.sh

[生成文件]

include vars.sh

然后shell脚本和Makefile可以共享相同的“信息源”。我发现了这个问题,因为我正在寻找可以在Gnu Make和shell脚本中使用的通用语法清单(我不关心哪个shell)。

编辑:轰炸并理解 $ {var} 。这意味着你可以连接等,     var =“一个字符串”     var = $ {var}“第二个字符串”

答案 6 :(得分:3)

我真的很喜欢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的情况下复制每个规则的名称没有定义。

答案 7 :(得分:1)

我的解决方案:(假设您拥有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中运行。

此方法的缺点是文件来源于每个目标,这可能是不合需要的。

答案 8 :(得分:1)

另一种可能的方法是创建一个sh脚本,例如run.sh,获取所需的脚本并在脚本中调用make。

#!/bin/sh
source script1
source script2 and so on

make 

答案 9 :(得分:0)

如果只需要一些已知的变量,可以选择在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

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

答案 10 :(得分:0)

如果您想将变量放入环境,以便将它们传递给子流程,那么您可以使用bash&#39; set -aset +a 。前者意味着,&#34;当我设置变量时,也设置相应的环境变量。&#34;所以这对我有用:

check:
    bash -c "set -a && source .env.test && set +a && cargo test"

这会将.env.test中的所有内容传递给cargo test作为环境变量。

请注意,这将允许您将环境传递给子命令,但它不允许您设置Makefile变量(无论如何都是不同的东西)。如果你需要后者,你应该尝试其中一个建议。

答案 11 :(得分:0)

根据您的Make和封闭外壳的版本,您可以通过evalcat以及通过&&链接调用来实现一个不错的解决方案:

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!

答案 12 :(得分:0)

找到了here的优雅解决方案:

ifneq (,$(wildcard ./.env))
    include .env
    export
endif

答案 13 :(得分:-1)

target: output_source
    bash ShellScript_name.sh

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