2013-10-12 44 views
0

我有一個文件,TMP包含:什麼導致這個奇怪的時間旅行與製造?

{ 
    "VolumeId": "vol--22222222", 
} 

和一個makefile,只有包含:如預期

\cp tmp latest 
grep VolumeId latest 
    "VolumeId": "vol--22222222", 
VolumeId: vol--22222222, 

MYFILE =latest 

x: 
    \cp tmp $(MYFILE) 
    grep VolumeId $(MYFILE) 
    @echo $(shell grep VolumeId $(MYFILE)) 

如果我運行make X,我得到。如果我修改文件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 

它看起來像所有的$(殼...)命令會在y配方的任何一行之前一起評估。

這有點令人吃驚(反直覺 - 這種奇怪設計的基本原理是什麼?)。如果shell命令有副作用,它會產生重要的後果。另外,我在製作手冊中找不到描述評估順序的任何文檔。


更新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. 

瘋狂。誰設計的?

+2

看起來在執行命令之前shell擴展已完成。 –

回答

2

你沒有告訴我們一切:當你第一次運行它時,你會迴應一個空行。相反,你會得到一個grep文件找不到的錯誤。

這就是決定性的提示:$ -expressions通過化妝的任何變體之前運行規則的命令進行評估。即在以後的每次運行中,都會看到上一次運行的文件內容。

Btw。您的主要反斜槓是虛假的,導致命令被傳遞給Shell,而不是由make直接執行。隨着makepp's內建命令(通過&前綴)和固定的依賴關係,這將是:

latest: tmp 
    &cp $(input) $(output) 
    &grep VolumeId $(output) 
    @&echo $(&grep VolumeId $(output)) 

不改變的問題,但通過適當的規則變量,使得它很明顯出了什麼問題。

+0

謝謝。當你說表達。你的意思是任何以$開頭的東西,或者任何形式爲$(function ...)的任何東西。 – user48956

+0

在運行配方之前,GNU make變量被擴展,並執行函數。配方執行時運行'$(SHELL)'中指定的shell,因此在你的配方中使用'$(shell ...)'意味着你首先執行shell來幫助確定當shell中的命令將被送入shell時配方被執行。您可以在GNU make手冊中查看這些東西,確保您使用的是您正在使用的GNU make版本的手冊。 – reinierpost

+0

順便說一下,在你的命令前應該做些什麼? – reinierpost

相關問題