GNU Make - 配方中的变量扩展
假设在工作目录中,我有:
$ find . | grep testfile
./testfile1
这是我的 Makefile:
list_files:
@echo "Show Files..."
@echo $(shell find . | grep testfile)
@touch testfile2
@echo $(shell find . | grep testfile)
@rm testfile2
使用 make
,我得到:
$ make list_files
Show Files...
./testfile1
./testfile1
为什么会发生这种情况?我期望它是这样的:
Show Files...
./testfile1
./testfile1 ./testfile2
那么我的问题是:
为什么规则内配方中的所有变量/函数在调用目标后可能同时扩展?
我从这个答案中找到了一个非常接近事实的解释:
您的尝试不起作用的原因是 make 将在开始第一行之前评估配方的所有行。
但那里没有提供参考资料,我只是无法说服自己相信GNU Make的这种工作机制。
有人可以提供一些线索吗?谢谢!
Say in the working directory, I have:
$ find . | grep testfile
./testfile1
This is my Makefile:
list_files:
@echo "Show Files..."
@echo $(shell find . | grep testfile)
@touch testfile2
@echo $(shell find . | grep testfile)
@rm testfile2
With make
, I got this:
$ make list_files
Show Files...
./testfile1
./testfile1
Why this happened? I expected it to be something like this:
Show Files...
./testfile1
./testfile1 ./testfile2
Then my question is:
Why all the variables/function in recipes inside a rule, are expanded likely simultaneously after target is invoked?
I have found an explanation from this answer that is pretty close to the truth:
The reason your attempt doesn't work is that make will evaluate all lines of the recipe before it starts the first line.
But there is no references provided there, I just cannot convinced myself of this working mechanism of GNU Make.
Could anyone give some clues? Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因为,对于不适用于您的情况的警告,
make
函数,例如$(shell ...)
在解析Makefile时,请评估,而不是在执行过程中食谱。他们不是。在目标食谱运行之前,它们会扩展。实际上,在
制作
之前,甚至确定是否应运行配方。只要手册。特别是请参见第8.14节, 函数 :
...指第3.7节, 代码> make 读取makefile ,特别是:
它还依靠第8.1节,语法 :
当然,“相同的规则”包括执行扩展时的规则。
您的配方应以目标外壳的语言编写,通常是
/bin/sh
。所有Make
函数和每个食谱中的变量引用将在任何食谱运行之前进行扩展,因此它们的扩展无法反映在当前make> make
运行期间运行任何配方的结果。尝试使用$(shell ...)
函数来做到这一点特别奇怪,因为您可以在配方中直接使用shell代码。Because, with one caveat that does not apply to your case,
make
functions such as$(shell ...)
are evaluated when the makefile is parsed, not during the execution of recipes.They're not. They are expanded before the target's recipe runs. In fact, before
make
even determines whether the recipe should be run.This is covered in the manual. See in particular section 8.14, The
shell
function:... which refers to section 3.7, How
make
Reads a Makefile, in particular:It also relies on section 8.1, Function Call Syntax:
"The same rules" of course includes the rules for when expansions are performed.
Your recipes should be written in the language of the target shell, usually
/bin/sh
. Allmake
functions and variable references in each recipe will be expanded before any recipe runs, so their expansions cannot reflect the results of running any recipe during the currentmake
run. It's particularly peculiar to try to use the$(shell ...)
function to do that, because you can just use shell code directly in a recipe.如评论中所述,在执行配方中的任何行之前,所有$(shell ...)和其他功能在执行任何行之前均已执行(扩展)。但是您可以延迟扩展:
这会产生预期的输出。注意双$$。 Make仍将在执行配方之前先扩展所有变量/功能,然后删除一个美元标志。执行配方行时,表达式将再次扩展。
当然,在此示例中,您最好没有$(shell)。但是,这本质上并不是一个坏主意。有时,您需要在扩展其他变量之前执行Shell命令,然后$(Shell)是微不足道的解决方案。
As explained in the comments, all $(shell ...) and other functions are executed (expanded) before executing any lines from the recipe. But you can delay the expansion:
This yields the expected output. Note the double $$. Make will still expand all variables/functions first before executing the recipe, and remove one of the dollar signs. The expressions will be expanded again, when executing the recipe lines.
Of course, you're better off without the $(shell) in this example. However, it's not inherently a bad idea. Sometimes you need to execute shell commands before expanding other variables, and then $(shell) is the trivial solution.