考虑以下 Makefile。
$(shell touch /tmp/example.txt)
FILE := /tmp/example.txt
CONTENTS = $(shell cat $(FILE); bash -c 'echo [debugging id: $$RANDOM]')
.PHONY: all
all:
@cat $(FILE)
@echo '$$(CONTENTS):' $(CONTENTS)
bash -c 'echo file-contents-$$RANDOM' > $(FILE)
@cat $(FILE)
@echo '$$(CONTENTS):' $(CONTENTS) # This line outputs the old contents. Why?
Run Code Online (Sandbox Code Playgroud)
它打印文件的内容,用新内容覆盖并再次打印内容。它显示为(在第二次拍摄之后make):
file-contents-1543
$(CONTENTS): file-contents-1543 [debugging id: 15172]
bash -c 'echo file-contents-$RANDOM' > /tmp/example.txt
file-contents-22441
$(CONTENTS): file-contents-1543 [debugging id: 151]
Run Code Online (Sandbox Code Playgroud)
旧内容file-contents-1543和新内容file-contents-22441(数字是随机的),但最后一行echo $(CONTENTS)不打印新内容。我认为该命令实际上在调试 id 显示时被调用了两次,但在将新内容写入文件之前,lazy 变量中的 shell 函数似乎已被执行。
我希望每次引用 Makefile 中的惰性变量时都会对其进行评估,该echo $(CONTENTS)命令始终打印最新的文件内容。我怎么了?
顺便说一句,我发现使用CONTENTS = $$(cat $(FILE))如我所料。我将使用它而不是 shell 函数,但是可以吗?
我希望每次引用 Makefile 中的惰性变量时都会对其进行评估, echo $(CONTENTS) 命令始终打印最新的文件内容。我怎么了?
首先,在 make 的俚语中,这些变量被称为recursive,而不是 lazy 。而且,是的,它们每次被引用时都会被扩展(即递归替换)$(CONTENTS)。考虑到这一点,$(eval...)并且$(shell...)(几乎所有看起来像$(...))也经历了相同的(递归)扩展程序(尽管有一些“副作用”),这种变量的每次扩展也可能导致某种“评估”或“执行”。
接下来,make 中的展开顺序有点特殊。特别是,配方(即开始[标签]的线)被扩展后的整个生成文件是(预)处理,但之前的配方的第一行得到由壳执行。我想这是你困惑的主要来源。
我发现使用 CONTENTS = $$(cat $(FILE)) 可以正常工作
$$是一种$在扩展过程后获得单个文字的方法。因此,$$(cat $(FILE))当扩展成为bash 中命令替换$(cat /tmp/example.txt)的合法语法时。这意味着它只能作为 bash 命令(配方行)的一部分工作。如果那是你想要的,那就没问题了。
| 归档时间: |
|
| 查看次数: |
821 次 |
| 最近记录: |