如何在使用 Make 时改进 $(call $(eval $(call))) 范式?
how to improve $(call $(eval $(call))) paradigm in using Make?
我编写通用的 makefile 和函数是为了方便用户,所以它们自然应该具有尽可能简单的界面。在定义函数时,我使用这种范式:
define FUNCTION
target:
endef
FUNCTION2 = $(eval $(call FUNCTION,))
现在,而不是告诉他们这样做
$(eval $(call FUNCTION,
参数))
我可以告诉他们这样做
$(call FUNCTION2,
参数)
哪个更简单。
在有人决定使用 .EXPORT_ALL_VARIABLES
之前,这一直很有效,因此我们的总代码 (SSCCE) 如下所示:
define FUNCTION
target:
endef
FUNCTION2 = $(eval $(call FUNCTION,))
.EXPORT_ALL_VARIABLES:
all:
echo OK
现在当你 make
这个时,你会得到:
Makefile:5: *** prerequisites cannot be defined in recipes. Stop.
好吧,我想这是因为配方 echo
子流程评估 "variable" FUNCTION2
,然后意外地将先决条件行放入配方中。或类似的东西。
所以我的问题是,谁应该受到指责?
我的范例是否有问题,我不应该使用它,因为用户无法使用 .EXPORT_ALL_VARIABLES
?如果是这样,有没有办法解决问题,让用户仍然可以调用简单的 FUNCTION2
?
或者 .EXPORT_ALL_VARIABLES
是一个邪恶的特性,不应该被使用?
在我的 non-recursive 构建系统 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
的哪个参数是什么意思,因为this_
变量具有描述性名称。
我个人认为.EXPORT_ALL_VARIABLES
是一个邪恶的特性,不应该被使用。但是,我认为这值得 GNU make 的增强请求:在扩展导出变量时不应该是 运行 eval
。
使用 unexport FUNCTION FUNCTION2
消除此错误。
然而我不得不同意@MadScientist 的观点.EXPORT_ALL_VARIABLES
是邪恶的。
它在执行每个配方之前强制执行所有递归变量的扩展,因此它可以轻松破坏任何复杂的构建系统。
IMO,有一种方法可以停止 auto-exported 变量的任何扩展。
唯一的安慰是几乎没有人使用那个 .EXPORT_ALL_VARIABLES
东西。
我编写通用的 makefile 和函数是为了方便用户,所以它们自然应该具有尽可能简单的界面。在定义函数时,我使用这种范式:
define FUNCTION
target:
endef
FUNCTION2 = $(eval $(call FUNCTION,))
现在,而不是告诉他们这样做
$(eval $(call FUNCTION,
参数))
我可以告诉他们这样做
$(call FUNCTION2,
参数)
哪个更简单。
在有人决定使用 .EXPORT_ALL_VARIABLES
之前,这一直很有效,因此我们的总代码 (SSCCE) 如下所示:
define FUNCTION
target:
endef
FUNCTION2 = $(eval $(call FUNCTION,))
.EXPORT_ALL_VARIABLES:
all:
echo OK
现在当你 make
这个时,你会得到:
Makefile:5: *** prerequisites cannot be defined in recipes. Stop.
好吧,我想这是因为配方 echo
子流程评估 "variable" FUNCTION2
,然后意外地将先决条件行放入配方中。或类似的东西。
所以我的问题是,谁应该受到指责?
我的范例是否有问题,我不应该使用它,因为用户无法使用 .EXPORT_ALL_VARIABLES
?如果是这样,有没有办法解决问题,让用户仍然可以调用简单的 FUNCTION2
?
或者 .EXPORT_ALL_VARIABLES
是一个邪恶的特性,不应该被使用?
在我的 non-recursive 构建系统 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
的哪个参数是什么意思,因为this_
变量具有描述性名称。
我个人认为.EXPORT_ALL_VARIABLES
是一个邪恶的特性,不应该被使用。但是,我认为这值得 GNU make 的增强请求:在扩展导出变量时不应该是 运行 eval
。
使用 unexport FUNCTION FUNCTION2
消除此错误。
然而我不得不同意@MadScientist 的观点.EXPORT_ALL_VARIABLES
是邪恶的。
它在执行每个配方之前强制执行所有递归变量的扩展,因此它可以轻松破坏任何复杂的构建系统。
IMO,有一种方法可以停止 auto-exported 变量的任何扩展。
唯一的安慰是几乎没有人使用那个 .EXPORT_ALL_VARIABLES
东西。