考虑以下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?
它将打印文件的内容,用新内容覆盖并再次打印内容。显示为(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]
旧内容为file-contents-1543
,新内容为file-contents-22441
(数字是随机的),但是最后一行echo $(CONTENTS)
不打印新内容。
我认为该命令实际上是调试ID所显示的两次,但是在将新内容写入文件之前,似乎执行了lazy变量中的shell函数。
我希望每次引用Makefile中的惰性变量时都会对其求值,echo $(CONTENTS)
命令始终会打印最新的文件内容。我怎么了?
顺便说一句,我发现使用CONTENTS = $$(cat $(FILE))
可以达到预期效果。我将用它代替shell函数,但是可以吗?
答案 0 :(得分:1)
我希望每次引用Makefile中的惰性变量时都会对其求值,echo $(CONTENTS)命令总是打印最新的文件内容。我怎么了?
首先,在make的语中,这些变量称为递归,而不是惰性的。而且,是的,每次使用$(CONTENTS)
进行引用时,它们都会扩展(即递归替换)。考虑到$(eval...)
和$(shell...)
(几乎像$(...)
一样)也经历了相同的(递归)扩展过程(尽管有一些“副作用”),每次扩展这样的变量也会导致某种“评估”或“执行”。
接下来,make中的扩展顺序有些特定。特别是,配方(即以[tab]开头的行)在整个emfile(预处理)后 后展开,但在配方的第一行之前由外壳执行。我想,这是您困惑的主要根源。
我发现使用CONTENTS = $$(cat $ {FILE))可以正常工作
$$
是一种在扩展过程之后获取单个文字$
的方法。因此,$$(cat $(FILE))
展开后变成$(cat /tmp/example.txt)
,这是bash中command substitution的合法语法。这意味着它将仅作为bash命令(配方行)的一部分工作。如果那是您想要的,那没关系。