为什么 GNU make 的 eval 将列表转换为标量?

为什么 GNU make 的 eval 将列表转换为标量?

我试图使用 eval 来定义一些 make 变量,但它似乎隐式地将列表转换为标量。我似乎不知道如何避免这种行为。这是我当前的 Makefile:

foo_man_srcs := a.c b.c

define GEN_OBJS =
    $(1)_srcs := a.c b.c
    $(1)_gen_objs := $(addprefix objdir/,$$($(1)_srcs:.c=.o))
    $(1)_man_objs := $(addprefix objdir/,$(foo_man_srcs:.c=.o))
endef

$(eval $(call GEN_OBJS,foo))

all:
    echo "foo_gen_objs: $(foo_gen_objs)"
    echo "foo_man_objs: $(foo_man_objs)"

这是我观察到的当前行为:

$ make
echo "foo_gen_objs: objdir/a.o b.o"
foo_gen_objs: objdir/a.o b.o
echo "foo_man_objs: objdir/a.o objdir/b.o"
foo_man_objs: objdir/a.o objdir/b.o

我的期望是 $(foo_gen_objs) 和 $(foo_man_objs) 都会计算出相同的值,但 eval 似乎将 $$($(1)_srcs) 视为标量而不是列表。我怎样才能解决这个问题?

答案1

解决方案非常简单:您应该转义 addprefix() 函数的 $ 符号:

define GEN_OBJS =
    $(1)_srcs := a.c b.c
    $(1)_gen_objs := $$(addprefix objdir/,$$($(1)_srcs:.c=.o))
    $(1)_man_objs := $$(addprefix objdir/,$(foo_man_srcs:.c=.o))
endef

但更重要的是了解如何自己调试此类问题。基本上,您只需将“eval”替换为“info”,make 将打印 eval 的输入而不是解析它。

在您的示例中,将“eval”替换为“info”,然后调用 make 会产生:

foo_srcs := a.c b.c
foo_gen_objs := objdir/$(foo_srcs:.c=.o)
foo_man_objs := objdir/a.o objdir/b.o

正如您所看到的,call() 在调用 eval() 之前扩展了 addprefix() 函数。如果你按照我上面写的那样修复你的 makefile,你将得到:

foo_srcs := a.c b.c
foo_gen_objs := $(addprefix objdir/,$(foo_srcs:.c=.o))
foo_man_objs := $(addprefix objdir/,a.o b.o)

相关内容