Makefile 我可以改为引用$call by name的位置参数吗?
通过$(eval$(call))定义规则族非常有用,如下所示:Makefile 我可以改为引用$call by name的位置参数吗?,makefile,Makefile,通过$(eval$(call))定义规则族非常有用,如下所示: define SIMPLE_TEMPLATE foo_$(1): echo foo $(1) endef $(foreach _,A B C,$(eval $(call SIMPLE_TEMPLATE,$_))) 这将创建目标foo_A、foo_B和foo_C。在一个更复杂的模板中,引用参数并用名称调用可能会更好;i、 e.$(消息)而不是$(1)。大概是这样的: define SIMPLE_TEMPLATE
define SIMPLE_TEMPLATE
foo_$(1):
echo foo $(1)
endef
$(foreach _,A B C,$(eval $(call SIMPLE_TEMPLATE,$_)))
这将创建目标foo_A
、foo_B
和foo_C
。在一个更复杂的模板中,引用参数并用名称调用可能会更好;i、 e.$(消息)
而不是$(1)
。大概是这样的:
define SIMPLE_TEMPLATE
MSG := $1
foo_$(MSG):
echo foo $(MSG)
endef
$(foreach _,A B C,$(eval $(call SIMPLE_TEMPLATE,$_)))
这几乎奏效了<代码>foo_A和
foo_B
按预期工作,但foo_C
不工作。有趣的是,将abc
更改为abcd
会导致targetfoo_C
开始工作。下面是我如何理解发生了什么:每次通过eval
都会为$(MSG)
分配一个值,但直到下一次eval
调用时,才会感知到该分配。同样,如果在循环中附加额外的过程,这看起来确实有效。但感觉不对。有没有一种“正确”的方法可以做到这一点,而不必进行额外的密码破解?根据定义方式(a:=…
或a=…
)和位置(在目标、先决条件、配方中…)在不同的可能时间进行递归扩展。简要说明这一点
我发现您的第二个Makefile存在两个不同的问题:
SIMPLE\u模板
中的$(MSG)
是在扩展$(foreach,A B C,…
)的过程中展开的,而不是在将结果作为make语法进行正常解析的过程中展开的。让我们一步一步地看一下:
- 扩展foreach的
$(eval $(call SIMPLE_TEMPLATE,A))) $(eval $(call SIMPLE_TEMPLATE,B))) $(eval $(call SIMPLE_TEMPLATE,C)))
的扩展是特殊的,它扩展了其参数并将其实例化为make构造。因此,要理解,我们必须首先扩展eval
。每个调用都替换调用
简单模板定义中的
。例如,传递给第一个$(1)
的是:eval
MSG := A foo_$(MSG): echo foo $(MSG)
- 但是,
参数的扩展将继续进行,直到没有可扩展的内容。对eval
的引用(尚未定义)将替换为空字符串,并且最终实例化的make构造为:MSG
MSG := A foo_: echo foo
echo foo
末尾的空格。与任何make构造一样,它们会依次展开,但这不会改变任何内容,因为没有其他内容可展开。在第二个eval
展开过程中,由于第一个MSG
的值为A
。因此,第二个eval
收到:
MSG := B
foo_$(MSG)
echo foo $(MSG)
从调用
,将其展开为:
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
target(但您有一个不需要的foo_
target…)
要在扩展$(foreach…
期间避免第一次过早扩展$(MSG)
,可以将$
符号加倍:
define SIMPLE_TEMPLATE
MSG := $(1)
foo_$$(MSG):
echo foo $$(MSG)
endef
如果我们一步一步地运行此操作,第一个调用将通过:
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)
但在这里,您遇到了第二个问题:
MSG
make变量。在第一阶段之后,它的值被解析为C
,并且您所拥有的等价于:
MSG := C
foo_A:
echo foo $(MSG)
foo_B:
echo foo $(MSG)
foo_C:
echo foo $(MSG)
结果将是:
$ make foo_A foo_B foo_C
echo foo C
foo C
echo foo C
foo C
echo foo C
foo C
可能不是您想要的。请注意,即使使用递归扩展的变量(MSG=…
),它也是一样的define SIMPLE_TEMPLATE
foo_$(1): MSG := $(1)
foo_$(1):
echo foo $$(MSG)
endef
(注意配方中的$
),其展开形式如下:
foo_A: MSG := A
foo_A:
echo foo $(MSG)
...
MSG_A := A
foo_A:
echo foo $(MSG_A)
...
或者,可能使用不同的构造变量名:
define SIMPLE_TEMPLATE
MSG_$(1) := $(1)
foo_$(1):
echo foo $$(MSG_$(1))
endef
扩展为:
foo_A: MSG := A
foo_A:
echo foo $(MSG)
...
MSG_A := A
foo_A:
echo foo $(MSG_A)
...
两者最终运行为:
$ make foo_A foo_B foo_C
echo foo A
foo A
echo foo B
foo B
echo foo C
foo C
可能更接近你的预期