以下を含むファイル tmp があります。
{
"VolumeId": "vol--22222222",
}
および以下のみを含むメイクファイル:
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,
...は?grep は異なる結果を返します! 2 番目のファイルには、コピー前のファイルのデータが含まれています。
走る
rm latest ; make x
私は得る:
\cp tmp latest
grep VolumeId latest
"VolumeId": "vol--4444444444",
何が起きてる?
GNU メイク 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 レシピの任意の行の前にまとめて評価されるように見えます。
これは少し驚くべきことです (そして直感に反します。この奇妙な設計の論理的根拠は何ですか?)。シェル コマンドに副作用がある場合、重要な結果が生じます。また、この評価の順序を説明しているドキュメントが make マニュアルに見つかりません。
更新 2
上記で特に奇妙なのは、評価の順序に関するメンタル モデルを思いつくのが難しいことです。レシピの各行の前に $(function ... ) という形式のルールが実行されるということですか? もしそうなら、なぜ $(CMD0) はレシピの前に評価され、$(CMD1) は評価されないのですか? CMD0に $(f ... )が含まれているのは本当です- CMD0 が遅延評価変数として宣言されていても (つまり、= ではなく := で宣言されています)、これを調べますか?
アップデート 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.
狂った。誰がこれを設計しましたか?