GNU make手册说eval函数扩展了参数,然后提供扩展的结果来生成解析器。以下内容来自GNU make manual。
The argument to the eval function is expanded, then the results of that expansion are parsed as makefile syntax.
我不太了解make解析器如何处理eval提供的文本,所以 我编写以下makefile进行测试。
define myprint
echo "this is a line"
endef
goal:
$(eval $(call myprint))
gcc -o goal test.c
我知道myprint
的正确调用应仅使用通话功能:$(call myprint)
并删除'标签'回声前的字符。我在这个表单中编写makefile只是为了测试eval函数。
我的期望:首先,eval函数会扩展myprint,这是一个以' Tab'开头的echo命令,以及' Tab'用于使扩展文本成为合法配方。然后,eval将扩展文本提供给制造商解析器,制造商解析器将文本识别为配方,然后运行它。由于命令合法,makefile应该正常运行。
但是,我遇到了这样的错误:
Makefile:6: *** recipe commences before first target. Stop.
有人可以解释为什么会产生这样的错误吗?
答案 0 :(得分:4)
该扩展的结果被解析为makefile语法
您对eval
的使用有所不同:您希望将其解析为shell语法。你可以写:
define myprint
echo "this is a line"
endef
goal:
$(myprint)
gcc -o goal test.c
或:
define myprint
echo "this is a $(1)"
endef
goal:
$(call myprint,line)
gcc -o goal test.c
因为在make扩展之后,配方是有效的shell语法。但不是你写的,因为eval
的扩展仍然被解释为make语法,而不是shell。为了说明eval
和call
的典型用法,请考虑以下事项:
define myprint
echo "this is a $(1)"
endef
define mygoal
$(1):
$$(call myprint,line)
gcc -o $(1) $(2).c
endef
$(eval $(call mygoal,goal,test))
它比两个第一个例子(没有eval
)更棘手,但它说明了eval
的真正目的:以编程方式实例化make构造。以下是它的工作原理,一步一步:
在其2阶段算法的第一阶段,make扩展了$(eval...
函数调用,即:
$(eval...
函数的参数($(call...
函数):
$(call...
函数(goal
和test
)的参数。在我们的案例中没有效果。$(1)
和$(2)
。mygoal
变量,该变量将$(1)
,$(2)
和$$(call...
替换为goal
,test
和{{1}分别。将结果实例化(在内存中)作为make构造,在这种情况下是完整的规则:
$(call...
第一阶段继续,但它对此实例化规则没有影响,因为配方在第二阶段由make扩展。
在第二阶段,当构建goal:
$(call myprint,line)
gcc -o goal test.c
目标时,make会在执行之前扩展配方,即:
goal
参数($(call myprint...
,无效)。line
。在此上下文中展开变量$(1)
,生成:
myprint
因此,所有这些都与我们编写规则相同:
echo "this is a line"
请注意goal:
echo "this is a line"
gcc -o goal test.c
的初始定义中的双$$
:
重要的是要意识到eval参数扩展了两次; 首先通过eval函数,然后是扩展的结果 当它们被解析为makefile语法时再次展开。这意味着你 可能需要为“$”字符提供额外的转义级别 使用eval。
答案 1 :(得分:3)
$(eval …)
需要一个语法上完整的makefile片段。它不能用于将标记粘贴到其他makefile结构中。也许手册并没有足够清楚地解释这一点,但是通过阅读它的论证来实现它就好像它是一个包含的makefile。
答案 2 :(得分:0)
我有一个关于你的例子的新问题,用于说明eval函数。
define myprint
echo "this is a $(1)"
endef
define mygoal
$(1):
$$(call myprint,line)
gcc -o $(1) $(2).c
endef
$(eval $(call mygoal,goal,test))
我们知道mygoal
首先通过调用扩展,然后通过eval扩展,然后通过make解析器扩展。我的问题是哪个函数扩展$$(call myprint,line)
$(call myprint,line)
,调用函数($(call mygoal,goal,test)
)或eval函数。
我的观点是当$$(call myprint,line)
调用mygoal而不是eval函数调用$(call mygoal,goal,test)
时会扩展$$(call myprint,line)
。我的理由是:因为eval函数将其输入视为makefile语法,并且mygoal
在$$(call myprint,line)
的配方中,并且从GNU手册中我们知道make不会扩展配方,直到它是使用(配方被推迟),我们可以得出结论 Picasso.with(getApplicationContext())
.load(url_detail_img)
.error(R.drawable.temp_img)
.into(thumb_img);
没有扩展。
实际上,问题的关键点是eval和call函数如何扩展其输入。 eval函数是否扩展了配方(如果其输入是完整的makefile规则,其中包含目标,先决条件和配方)?
答案 3 :(得分:0)
@RenaudPacalet,我写了下面的makefile来测试是否扩展了call' eats'一美元。
define myprint
echo "In my print $$(ls)"
endef
goal:
$(call myprint)
$(info $(call myprint))
gcc -o goal test.c
它的输出是:
echo "In my print $(ls)"
echo "In my print $(ls)"
In my print call.mk ... (files list)
当$(call myprint)
正确输出"In my print $(ls)"
时,必须首先将其扩展为echo "In my print $$(ls)"
,然后将其扩展为正确的shell命令echo "In my print $(ls)"
。所以我认为通话功能并没有“吃掉”。一美元。
另一个证据是信息功能的输出。 GNU make手册说:
$(info text…)
This function does nothing more than print its (expanded) argument(s) to standard output.
从手册中我们可以推断make会扩展info函数的参数。由于信息的输出为echo "In my print $(ls)"
,因此扩展前的参数应为echo "In my print $$(ls)"
。因此,我们可以得出结论,呼叫功能并没有“吃”。一美元。