我在make文件中立即分配变量时遇到问题,使用:=与分配了+ =的变量结合使用。例如:
VAR := a
VARS += $(VAR)
rule1:
echo "$(VARS)"
VAR := b
VARS += $(VAR)
rule2:
echo "$(VARS)"
当我运行make时,无论规则如何,都会打印" b b"。令我感到困惑的是,如果我使用以下make文件:
VARS += a
rule1:
echo "$(VARS)"
VARS += b
rule2:
echo "$(VARS)"
它打印" a b"无论规则如何,这都是我所期望的。根据制作手册https://www.gnu.org/software/make/manual/html_node/Reading-Makefiles.html:
我们说如果在第一次发生时就会立即扩展 阶段:在这种情况下,make将扩展任何变量或函数 解析了作为makefile的构造部分。
立即:=立即
立即+ =延迟或立即
对于追加运算符'+ =',考虑右侧 如果变量先前已设置为简单变量,则立即生效 (':='或':: ='),否则延期。
如果:=实际上是立即的,并且立即变量在解析时被扩展,正如make手册所说的那样,那么我希望这些文件具有相同的行为。为什么这不是真的?我认为这可能是make文档中的错误或make中的错误。
答案 0 :(得分:3)
您缺少的是配方行(规则体)在解析时不会扩展(最多可以部分扩展,考虑自动变量,如$@
和$^
例如)而是在规则执行时扩展。
您在上面引用的手册部分的最后一部分How make
Reads a Makefile中介绍了这一点:
规则定义
规则总是以相同的方式扩展,无论形式如何:
immediate : immediate ; deferred deferred
也就是说,目标和先决条件部分会立即展开,并且用于构造目标的配方始终是延迟的。对于显式规则,模式规则,后缀规则,静态模式规则和简单的先决条件定义,此一般规则适用。
因此,如果您认为分配是正确的,那么您错过了配方上下文中的扩展不是。因此,在每个顶级任务完成后,配方始终扩展。
此外,对于第一个示例,您从未将VARS
设置为简单扩展,因此默认为递归扩展,因此在您编写时:
VAR := a
VARS += $(VAR)
并认为你在做:
VAR := a
VARS += a
你不是。
您实际上正在执行字面编写并将$(VAR)
存储在$(VARS)
的值中,以便在完成时$(VARS)
的值为$(VAR) $(VAR)
然后,自然,扩展为b b
。
如果您将VARS :=
添加到第一个makefile示例的顶部,您将获得a b
,因为那时VARS
只是展开并展开$(VAR)
+=
分配时间)。