我无法弄清楚使用GNU Make 3.81中带foreach循环的条件定义变量的正确语法。
一个简单的makefile
SET := A B C
define da_loop
ifeq ($(S), A)
T := equals_A
else
T := not_equals_A
endif
out_$(S):
echo "$(S) $$(T)"
endef
$(foreach S, $(SET), $(eval $(call da_loop, $S)))
预期输出:
$ make out_A out_B out_C
echo "A equals_A"
A equals_A
echo "B not_equals_A"
B not_equals_A
echo "C not_equals_A"
C not_equals_A
实际输出:
$ make out_A out_B out_C
echo "A not_equals_A"
A not_equals_A
echo "B not_equals_A"
B not_equals_A
echo "C not_equals_A"
C not_equals_A
将“评估”更改为“信息”在我看来应该是可行的:
ifeq (A, A)
T := equals_A
else
T := not_equals_A
endif
out_A:
echo "A $(T)"
ifeq (B, A)
T := equals_A
else
T := not_equals_A
endif
out_B:
echo "B $(T)"
ifeq (C, A)
T := equals_A
else
T := not_equals_A
endif
out_C:
echo "C $(T)"
我已经试过可以想到的多余的$,引号,= vs:=的每一种组合,但都没有奏效。有什么想法吗?
问题与循环,eval
等无关。问题比这更简单,更根本:在make中,变量是[[全局定义的,并且所有规则仅在整个makefile具有被解析。 info
技巧实际上是DID向您显示问题。让我们简化一下:
T := equals_A
out_A:
echo "A $(T)"
T := not_equals_A
out_B:
echo "B $(T)"
T := not_equals_A
out_C:
echo "C $(T)"
问题是,所有变量赋值都在读入Makefile时发生,但是直到make生成目标并决定运行配方时,配方扩展才发生。因此,您的makefile可以等效地写为:
T := equals_A T := not_equals_A T := not_equals_A out_A: echo "A $(T)" out_B: echo "B $(T)" out_C: echo "C $(T)"
现在您可以看到为什么会得到自己的行为。有许多种方法可以“修复”此问题,哪种方法最合适取决于您实际在实际makefile中要执行的操作。一个非常简单的选项是使用target-specific variables,如下所示:
SET := A B C define da_loop ifeq ($(S), A) out_$(S): T := equals_A else out_$(S): T := not_equals_A endif out_$(S): echo "$(S) $$(T)" endef $(foreach S, $(SET), $(eval $(call da_loop, $S)))
通过使用此选项,您已指定每个T
变量都绑定到该特定目标的范围,并且每个目标可以具有不同的值。其他选项将构造为变量名称,或者使用$(if ...)
函数将值直接扩展到配方中,而不是将其设置为单独的变量。]>