Makefile `export` 将变量类型从简单扩展更改为递归扩展

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

考虑以下简单示例:

ARGS := -a -b
$(info args = $(ARGS))

DIR := foo
ARGS += ../$(DIR)/lib.a
$(info args = $(ARGS))

DIR := bar
$(info args = $(ARGS))

此输出(

make
在当前目录中)(如我所料):

args = -a -b
args = -a -b ../foo/lib.a
args = -a -b ../foo/lib.a
make: *** No targets.  Stop.

也就是说,

ARGS
是一个简单扩展变量,所以没有重新替换。它没有发现
DIR
从“foo”更改为“bar”。到目前为止,一切都很好。


但是,现在我尝试使用递归 makefile 来完成它。在父 makefile 中,我有第一个块,其中包含

export
命令(将所有变量导出到子级)和递归调用:

ARGS := -a -b
$(info args = $(ARGS))

export

default:
    $(MAKE)   -C child/

在子 makefile 中,我有其余部分,未修改:

DIR := foo
ARGS += ../$(DIR)/lib.a
$(info args = $(ARGS))

DIR := bar
$(info args = $(ARGS))

但是,现在的输出是:

args = -a -b
make   -C child/
make[1]: Entering directory '[...]/child'
args = -a -b ../foo/lib.a
args = -a -b ../bar/lib.a
make[1]: *** No targets.  Stop.
make[1]: Leaving directory '[...]/child'
make: *** [Makefile:14: default] Error 2

现在,它确实拾取

DIR
从“foo”更改为“bar”,重新替换。也就是说,不知何故,
export
命令更改了ARGS
的类型
(在子进程中) )到递归扩展变量

export
(再次,这里)的描述似乎表明这是不可能的。具体来说,它将
export :=
export =
进行了对比,并表示它们具有不同的效果。我们还可以通过用非常明确的内容替换父 makefile 中的代码来直接测试:

export ARGS := -a -b

default:
    $(MAKE)   -C child/

然而,这会在子进程中产生与以前相同的不需要的递归扩展!

make --version
将自己报告为“GNU Make 4.3”。


发生了什么事以及如何导出变量以便它们在子级中保持简单扩展?

recursion makefile variable-expansion
1个回答
0
投票

您对手册读得太多了。说明书上说:

export foo := bar

与以下行为相同:

foo := bar
export foo

确实如此。但这绝对没有说明子品牌中

foo
的行为。

实际上所有导出的 make 变量都是通过标准 POSIX 环境导出的,作为标准 POSIX 环境变量。环境变量中不存在“简单”变量与“递归”变量之类的东西,只有变量。

当 make 准备好调用配方中的命令时(无论该命令是编译器还是 make 的另一个实例或其他任何东西:这只是一个新的子进程),它将遍历所有导出的变量,展开它们,并将它们添加到子流程的环境中,然后调用子流程。

如果子进程是 make 的另一个实例,那么 make 将检索所有环境变量(一如既往)并将它们作为递归变量导入,并使用它们作为 make 变量具有的任何值。 Make 不知道父实例使用了简单变量,父实例也无法通过环境告诉子实例。

如果你想强制变量的简单性,你可以使用赋值而不是附加:

ARGS := $(ARGS) ../$(DIR)/lib.a
© www.soinside.com 2019 - 2024. All rights reserved.