SIMPLE_TEMPLATE 中的 $(MSG) 在扩展 $(foreach _,A B C,... 期间被扩展,而不是在正常解析结果时作为 make 语法。让我们一步一步来看看:
-
foreach的扩展:
$(eval $(call SIMPLE_TEMPLATE,A)))
$(eval $(call SIMPLE_TEMPLATE,B)))
$(eval $(call SIMPLE_TEMPLATE,C)))
-
eval 的扩展很特殊,它扩展了它的参数并将其实例化为一个 make 构造。所以,要理解,我们必须先扩展call。每个都替换SIMPLE_TEMPLATE 定义中的$(1)。例如,传递给第一个eval 的是:
MSG := A
foo_$(MSG):
echo foo $(MSG)
-
但是,eval 参数的扩展将继续,直到没有任何东西可以扩展。对尚未定义的 MSG 的引用被空字符串替换,最终实例化的 make 构造是:
MSG := A
foo_:
echo foo
echo foo 末尾有一个(不可见的)空格。作为任何 make 构造,它们会依次扩展,但这不会改变任何东西,因为没有其他东西可以扩展。在第二个eval 的扩展过程中,这一次,MSG 的值是A,这要感谢第一个。所以,第二个eval 收到:
MSG := B
foo_$(MSG)
echo foo $(MSG)
来自call,将其扩展为:
MSG := B
foo_A
echo foo A
并将其实例化为 make 构造。这些 make 构造再次扩展(与任何其他 make 构造一样),但它不再更改任何内容。同样,第三个eval 实例化:
MSG := C
foo_B
echo foo B
所以,总而言之,将被实例化为 make 构造的是:
MSG := A
foo_:
echo foo
MSG := B
foo_A:
echo foo A
MSG := C
foo_B:
echo foo B
而且您没有任何foo_C 目标(但您有一个不需要的foo_ 目标...)
要在$(foreach... 扩展期间避免$(MSG) 的第一次和过早扩展,您可以将$ 符号加倍:
define SIMPLE_TEMPLATE
MSG := $(1)
foo_$$(MSG):
echo foo $$(MSG)
endef
如果我们一步一步运行,第一个call 将通过:
MSG := A
foo_$$(MSG):
echo foo $$(MSG)
到第一个eval,它将扩展为:
MSG := A
foo_$(MSG):
echo foo $(MSG)
(每个 $$ 吃一个 $)并将其实例化为 make 构造。这些新的 make 构造也将被扩展,就像任何其他 make 构造一样,它将给出:
MSG := A
foo_A:
echo foo $(MSG)
(配方中的$(MSG) 尚未扩展,因为在配方中,扩展被推迟到第二阶段,并且仅在选择执行该配方时发生)。在$(foreach _,A B C,... 的第一次扩展之后,您拥有的是:
MSG := A
foo_A:
echo foo $(MSG)
MSG := B
foo_B:
echo foo $(MSG)
MSG := C
foo_C:
echo foo $(MSG)
但是在这里,你遇到了第二个问题: