为方便用户,我编写了通用的makefile和函数,因此它们自然应该具有最简单的接口。在定义函数时,我使用以下范例:
define FUNCTION
target: $1
endef
FUNCTION2 = $(eval $(call FUNCTION,$1))
现在,不要告诉他们这样做
$(eval $(call FUNCTION,
参数))
我可以告诉他们这样做
$(call FUNCTION2,
参数)
更简单。
这一直很吸引人,直到有人决定使用.EXPORT_ALL_VARIABLES
,这样我们的总代码(SSCCE)如下所示:
define FUNCTION
target: $1
endef
FUNCTION2 = $(eval $(call FUNCTION,$1))
.EXPORT_ALL_VARIABLES:
all:
echo OK
现在make
,您得到:
Makefile:5: *** prerequisites cannot be defined in recipes. Stop.
好吧,我想这是因为配方echo
子进程评估了“变量” FUNCTION2
,然后意外地将前提行放入了配方中。或类似的东西。
所以我的问题是,应该责怪谁?
我的范例是否有误,我不应该使用它,因为用户随后无法使用.EXPORT_ALL_VARIABLES
?如果是这样,有没有办法解决问题,以便用户仍然可以调用简单的FUNCTION2
?
或者.EXPORT_ALL_VARIABLES
是邪恶的功能,不应该使用吗?
答案 0 :(得分:1)
我个人认为.EXPORT_ALL_VARIABLES
是一个邪恶的功能,不应使用。但是,我认为这值得对GNU make进行增强请求:扩展用于导出的变量时,它不应运行eval
。
答案 1 :(得分:1)
使用unexport FUNCTION FUNCTION2
消除此错误。
但是我必须同意@MadScientist的观点,.EXPORT_ALL_VARIABLES
是邪恶的。
在执行每个配方之前,它会强制执行所有递归变量的扩展,因此可以轻松破坏任何复杂的构建系统。
IMO,有一种方法可以停止自动导出变量的任何扩展。
唯一的安慰是几乎没有人使用.EXPORT_ALL_VARIABLES
这种东西。
答案 2 :(得分:-1)
在我的非递归构建系统prorab中,我使用eval
,但没有call
。
我通过this_
前缀变量传递参数,如下所示:
include prorab.mk
this_name := myapp
this_cxxflags += -Wall
this_cxxflags += -DDEBUG
this_cflags += -Wall
this_ldlibs += -lpthread
this_srcs += main.cpp myapp.cpp legacy.c
$(eval $(prorab-build-app))
因此,eval
仍然存在,但是插入变量而不是call
使其更短,并且用户不必记住call
的哪个参数意味着什么,因为{{ 1}}变量具有描述性名称。