Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Variables Makefile变量初始化和导出_Variables_Makefile_Export - Fatal编程技术网

Variables Makefile变量初始化和导出

Variables Makefile变量初始化和导出,variables,makefile,export,Variables,Makefile,Export,我希望苹果作为命令的输出,但它是空的,这让我想到导出和:=变量扩展在不同的阶段进行。如何克服这个问题?运行makefile somevar := apple export somevar update := $(shell echo "v=$$somevar") all: @echo $(update) 为我提供(环境中未定义foo) 尝试使用带引号的表单(update:=“v=$$somevar”),并在命令运行时让shell处理扩展(您仍然需要导出)问题是export将变量导出到

我希望苹果作为命令的输出,但它是空的,这让我想到导出和
:=
变量扩展在不同的阶段进行。如何克服这个问题?

运行makefile

somevar := apple
export somevar
update := $(shell echo "v=$$somevar")

all:
    @echo $(update)
为我提供(环境中未定义foo)


尝试使用带引号的表单(
update:=“v=$$somevar”
),并在命令运行时让shell处理扩展(您仍然需要导出)

问题是
export
将变量导出到命令使用的子shell;它在其他作业中不可扩展。因此,不要试图从规则之外的环境中获取它

$ make
>
>apple

$ make foo=bar
>
>apple

$ export foo=bar; make
>bar
>apple

$ export foo=bar; make foo=bar
>bar
>bar
包含关键指针:对于GNU
make
,标有
export
变量仅可用于[为]配方命令启动的shell(作为规则一部分的命令),遗憾的是不可用于调用
$(shell…
(他们只看到
make
启动时看到的环境)

有一个解决方法,但是:将导出的变量作为环境变量显式地传递给
shell
函数:

somevar := apple
export somevar

update1 := $(shell perl -e 'print "method 1 $$ENV{somevar}\n"')
# Make runs the shell command, the shell does not know somevar, so update1 is "method 1 ".

update2 := perl -e 'print "method 2 $$ENV{somevar}\n"'
# Now update2 is perl -e 'print "method 2 $$ENV{somevar}\n"'

# Lest we forget:
update3 := method 3 $(somevar)

all:
    echo $(update1)
    $(update2)
    echo $(update3)
    perl -e 'print method 4 "$$ENV{somevar}\n"'
通过在shell命令前面加上
=
,该定义将作为环境变量添加到命令所看到的环境中—这是一个通用的shell功能

警告:@Kaz在一篇评论中指出,如果
$(somevar)
包含某些字符,则此方法会出现错误,因为变量扩展是逐字(无转义),这可能会破坏生成的shell命令,并建议以下变体也可用于嵌入式
实例
(将输入值拆分为单引号的子字符串,并在其中拼接引号
):

这应该适用于除多行值以外的所有值(这很少见;我知道没有多行值的解决方法)

另一方面,literal
$
chars.in值必须表示为
$
,否则
make
将它们解释为对自身变量的引用

注意,我故意没有选择OP的原始语句,
update:=$(shell echo“v=$$somevar”)
,用于演示,因为它包含一个使问题变得混乱的陷阱:由于shell如何计算命令行,
somevar=apple echo v=$somevar
不会计算为
v=apple
,因为
$somevar
引用在
somevar=apple
生效之前已展开。为了达到预期效果在这种情况下,您必须使用两条语句:
update:=$(shell export somevar=“$(somevar)”;echo“v=$$somevar”)


关于缺陷与功能之争:


虽然可以说,
shell
函数应该看到与配方命令相同的环境,但文档没有做出这样的承诺-请参阅。相反,只提到让配方命令可以使用导出的变量。

尽管
export
不能很好地使用
$(shell…)
,有一个简单的解决方法。我们可以通过命令行将数据传递给shell脚本

当然,environment Passation对转义和引用的问题很健壮。但是,shell语言有一个单引号引用方法
“…”
,它可以处理所有事情。唯一的问题是,无法在其中获取单引号;但当然,这可以通过终止引号、反斜杠转义nee来解决删除单个报价并开始新报价:换句话说:

update := $(shell somevar='$(subst ','\'',$(somevar))' perl -e 'print "$$ENV{somevar}"')
在由
$(shell…
执行的shell脚本中,我们只生成一个形式为
var='$(…)'
的变量赋值,其中
$(…)
是一些make表达式,它插入适当的转义材料。因此,
Makefile

ab'cd -> 'ab'\''cd'
$ make
cat file.txt
apple with 'quoted' "stuff" and dollar $signs
export somevar
update := $(shell env > file.txt)
样本运行:

somevar := apple with 'quoted' "stuff" and dollar $$signs

shell_escape = $(subst ','\'',$(1))

update := $(shell v='$(call shell_escape,$(somevar))'; echo $$v > file.txt)

.phony: all

all:
    cat file.txt
如果要将环境变量与命令通信,可以使用shell语法
VAR0=val0 VAR1=val1…VARn=valn command arg…
。这可以通过对上面的
Makefile
进行一些小改动来说明:

ab'cd -> 'ab'\''cd'
$ make
cat file.txt
apple with 'quoted' "stuff" and dollar $signs
export somevar
update := $(shell env > file.txt)
运行:

file.txt
包含一个环境变量转储,在这里我们可以看到
somevar
。如果GNU Make中的
export
做了正确的事情,我们就可以做到:

$ make
grep somevar file.txt
somevar=apple with 'quoted' "stuff" and dollar $signs
但最终结果是一样的

由于您想要的最终结果是
echo$(update)
,因此您无论如何都会
shell\u转义
,即使GNU Make将导出的变量传递到
$(shell…

ab'cd -> 'ab'\''cd'
$ make
cat file.txt
apple with 'quoted' "stuff" and dollar $signs
export somevar
update := $(shell env > file.txt)
输出:

somevar := apple with 'quoted' "stuff" and dollar $$signs

shell_escape = $(subst ','\'',$(1))

update := $(shell v='$(call shell_escape,$(somevar))'; echo $$v)

.phony: all

all:
    @echo '$(call shell_escape,$(update))'
    @echo $(update)

我需要保持shell函数不在target命令中的方式,因为它在现实生活中有条件语句。+1用于显示变量;短的是:(a)
$(shell…
只看到
make
启动时自己的环境中已经存在的变量;(b)在
make
的命令行上定义变量会覆盖makefile中相同名称的定义。使用第一个表达式“apple”的输出如何,并且在makefile之外不做任何事情?事实上这是一个bug[这不是固定的,也许永远也不会。谢谢,我会尽量不用奇怪的makefile问题来打扰你。@Michael:从我对GNUMake手册的阅读来看,这不是一个bug。(而且你不必在我回答的评论前面加上@Beta。)这并不奇怪。我需要这个。为什么我需要这个?因为环境是将任意字符串传递给外部脚本的唯一防弹方法。例如,假设我有一个变量V,它包含以下内容:各种类型的引号、重要的shell元字符(如美元)、反斜杠转义符等等。我想要一个shell脚本来se变量$V.@Kaz:听起来很危险,但可行。上面的方法之一是吗