我有一个文件,tmp包含:
{
"VolumeId": "vol--22222222",
}
和一个makefile,只包含:
MYFILE =latest
x:
\cp tmp $(MYFILE)
grep VolumeId $(MYFILE)
@echo $(shell grep VolumeId $(MYFILE))
如果我运行make x,我会得到:
\cp tmp latest
grep VolumeId latest
"VolumeId": "vol--22222222",
VolumeId: vol--22222222,
正如所料。如果我修改文件tmp,替换2的机智4,我得到:
\cp tmp latest
grep VolumeId latest
"VolumeId": "vol--44444444444",
VolumeId: vol--22222222,
...是吧? greps返回不同的结果!第二个包含之前文件中的数据。
我跑
rm latest ; make x
我明白了:
\cp tmp latest
grep VolumeId latest
"VolumeId": "vol--4444444444",
这里发生了什么?
GNU Make 3.81。 VMWare 5上的Ubuntu 12.04。
更新1
这是一个更明确的例子
CMD0 =$(shell date +"%s.%N")
CMD1 =date +"%s.%N"
CMD2 =date +"%s.%N"
y:
@sleep 2
@date +"%s.%N" # 2nd
@echo $(CMD0) # 1st A
@sleep 2
@date +"%s.%N" # 3rd
@sleep 2
@$(CMD1) # 4th
@sleep 2
@echo $(shell $(CMD2) ) # 1st B
输出:
1381596581.761093768
1381596579.743610973
1381596583.769058027
1381596585.774766561
1381596579.751625601
看起来所有$(shell ...)命令在y配方的任何行之前一起评估。
这有点令人惊讶(反直觉 - 这个奇怪设计的理由是什么?)。如果shell命令有副作用,它会产生重要的后果。另外,我在make手册中找不到描述此评估顺序的任何文档。
更新2
上述特别奇怪的是,很难为评估顺序提出心理模型。是否在表格的每一行之前执行了形式的任何规则$(function ...)?如果是这样,为什么在配方之前评估$(CMD0),而不是$(CMD1)。确实CMD0 包含 a $(f ...) - 确实会看到这一点,即使CMD0被声明为延迟评估变量(即声明为= not:=)?
更新3
将其简化为必要组件:
notSafe:
backup-everything # Format executed even if backup fails
echo $(shell format-disk) | tee log.txt #
CMDX =$(shell format-disk)
alsoNotSafe:
backup-everything # Format executed even if backup fails
echo $(CMDX) | tee log.txt # Even though CMDX is a delayed evaluation variable
CMDZ =format-disk
safe:
backup-everything # Works as expected.
$(CMDZ) | tee log.txt # Evaluation of CMDZ is delayed until line is executed.
疯狂。谁设计了这个?
答案 0 :(得分:2)
你没有告诉我们所有事情:当你第一次跑它时,你会回响一条空行。相反,你得到一个找不到grep文件的错误。
这是决定性的提示:$
- 表达式由运行规则命令之前的任何变种评估。即在以后的每次运行中,您都会看到上一次运行的文件内容。
顺便说一下。你的前导反斜杠是假的,导致命令被传递给Shell,而不是由make直接执行。使用makepp's内置命令(以&
为前缀)和固定的依赖关系:
latest: tmp
&cp $(input) $(output)
&grep VolumeId $(output)
@&echo $(&grep VolumeId $(output))
这不会改变问题,但通过使用适当的规则变量,可以明显地解决问题。