如何配置 GNU Make 将导出的变量传递给 shell 函数?

问题描述 投票:0回答:3

我在 GNU Make 中遇到了一个意想不到的奇怪现象,并且找不到合理配置它的方法。我将

SHELL
分配给我自己设计的自定义 shell,但是导出哪些变量的问题很容易用简单的 bash shell 重现:

SHELL := /bin/bash

export FOO := bar

.PHONY: all a b c

all: a b

a:
    @echo A: $$(env | grep FOO)

b:
    @echo B: $(shell env | grep FOO)

c:
    @echo === main target ===
    @echo $$(env | sed -e 's/=.*//')
    @echo === shell function ===
    @echo $(shell env | sed -e 's/=.*//')

这会产生一些意想不到的结果:

$ make
A: FOO=bar
B:
$ FOO=baz make
A: FOO=bar
B: FOO=baz

通信变量中所述,导出的

FOO
变量作为环境变量公开给在配方中运行行的shell。令人意想不到的是, shell函数没有得到同样的待遇!事实上,快速浏览一下
make c
中出现的内容,有几个变量没有被传递。我可以通过手动传入每个变量来解决这个问题(例如
$(shell FOO="$(FOO)" env)
),但这很快就会变得愚蠢(而且危险)。

这是特别有问题的,因为我希望导出的变量是

PATH
。事实上,构建我的目标的 shell 有一个
PATH
u200c 变量,而在 shell 函数中运行的任何内容都有不同的
PATH
,这是有问题的。如果你看一下完整的环境

如何标记

Makefile
环境中的一些变量,以便它们作为环境的一部分自动传递到从 shell 函数运行的 shell?

makefile gnu-make
3个回答
1
投票

正如@MadScientist 所指出的,

$(shell ...)
未传递导出变量。根据具体情况,如果环境变量的数量已知,则可以在 shell 命令中使用显式变量。例如

c:
    @echo === shell function ===
    @echo $(shell FOO=$FOO env | sed -e 's/=.*//')

当然,这个解决方案假设可以枚举所有要传递的变量,并且变量的数量相当小,否则代码会变得很难看。

作为替代方案,请考虑使用临时文件,而不是使用值来传递值

c:
    # env var are set, store result in var.txt
    do-something > var.txt
    # Uses the result of the previous step, from var.txt
    step2 $$(cat var.txt)

0
投票

默认 make 接收环境变量。如果导出并取消设置 make 变量,则该 make 变量将具有相应环境变量的值并出现在所有 shell 上下文中。

make -e
将环境变量作为覆盖而不是 make 变量,覆盖 make 内部设置的变量。因此,通常更喜欢
make -e
从调用上下文继承 shell 环境变量。

因此,要使其正常工作,只需导出您想要在配方执行环境中出现的变量名称即可。我还没有测试过非 sh-family

SHELL
替代品,比如 python:

# makefile

# export the var in make!
export FOO

# '$$' escapes the '$', so you are seeing the shell version of the variable
# @ prefixed recipes do not print
env:
  @echo "FOO: $$FOO"              # normal env override
  @echo $(shell echo FOO: $(FOO)) # make var value in $(shell ...) from calling env
  @echo $(shell echo FOO: $$FOO)  # env overridden in $(shell ...)
# shell

$ make env
FOO:
FOO:
FOO:

$ export FOO="BAR"
$ make -e env
FOO: BAR
FOO: BAR
FOO: BAR

这是我编写的第二个 makefile,以类似于原始问题的方式证明它:

export FOO

foo1=$(shell echo FOO: $(FOO))
foo2=$(shell echo FOO: $$FOO)
env:
  @echo "FOO: $$FOO"
  @echo $(foo1)
  @echo $(foo2)

底线:导出您想要出现在子 shell 中的变量,并且当您想要严格继承环境变量并覆盖任何内部定义时更喜欢使用

make -e

内部定义也可以根据环境来编写。因此,如果您是唯一作者,您可以定义变量以适应环境,删除

-e
:

export FOO
FOO?=BIZ

-1
投票

Shell 函数的作用是解析输出并扩展它在其中找到的变量。考虑以下代码:

export BANANA = I am a banana
foo: G := $(shell echo who am I? '$$'BANANA)
foo:
    @echo $(G)

输出:我是谁?我是香蕉

© www.soinside.com 2019 - 2024. All rights reserved.