0

以下を含むファイル 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.

狂った。誰がこれを設計しましたか?

4

1 に答える 1

2

すべてを伝えているわけではありません。最初に実行すると、空の行がエコーされます。代わりに、grep file not found エラーが発生します。

そして、それが決定的なヒントです: $-expressions は、ルールのコマンドを実行する前に、make のバリアントによって評価されます。つまり、その後の実行ごとに、前の実行のファイルの内容が表示されます。

ところで。先頭のバックスラッシュは誤っており、コマンドが make によって直接実行されるのではなく、シェルに渡されます。makepp組み込みコマンド (接頭辞&) と固定依存関係を使用すると、次のようになります。

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

これで問題が変わるわけではありませんが、適切なルール変数を使用することで、何が問題なのかが明らかになります。

于 2013-10-12T12:00:02.960 に答える