web-dev-qa-db-ja.com

GNU make?で注文のみの前提条件が正しく機能しない

注文のみの前提条件に問題があります。これらは最初はまったく実行されません。注文のみの前提条件が機能する方法を誤解していますか?

次のmakeスクリプト:

.PHONY: mefirst mefirst2

mefirst:
    @echo "I'm first!"

mefirst2:
    @echo "I'm first too!"

normaltarget: normaltarget2 | mefirst2
    @echo "normaltarget done"

normaltarget2: a b c 
    @echo "normaltarget2 done"

helloworld: normaltarget | mefirst
    @echo "helloworld done"

.DEFAULT_GOAL := go
go: helloworld
    @echo "go done"

a:
    @echo a
b:
    @echo b
c:
    @echo c

...以下を出力します。

a
b
c
normaltarget2 done
I'm first too!
normaltarget done
I'm first!
helloworld done
go done

...私が期待するものの代わりに:

I'm first!
I'm first too!
a
b
c
normaltarget2 done
normaltarget done
helloworld done
go done

私は何が間違っているのですか?

22
George André

注文のみの前提条件が機能する方法を誤解していますか?

はい、それはそれがどのように見えるかです。

「注文のみ」という名前はやや紛らわしいです。 |の背後にある前提条件は、単一のターゲットの前提条件のリスト内でレシピの実行順序を変更するためではなく、特定のターゲットを他のターゲットよりも先に作成することが唯一の目的であるため、「順序のみの前提条件」と呼ばれます。ブートストラップのように。以下のユーザーbobbogoによって正確に説明されているように(-修正してくれてありがとう):makeがターゲットの前提条件を再構築することを決定した場合、その前提条件のレシピを実行します。さて、通常の前提条件の場合、この更新はターゲットが古くなっていることを意味し、makeはターゲットのレシピを実行する必要があります。一方、注文のみの前提条件の場合、makeはターゲットを更新が必要であるとマークしません。

たとえば、ディレクトリ内のオブジェクトを作成する前にディレクトリを作成する必要があるユースケースについては、セクション 前提条件のタイプ を参照してください。

この例を見てくださいmakefile

a: b
    touch a

b: c
    touch b

c:
    touch c

x: | y 
    touch x

y: | z 
    touch y

z:
    touch z

ご覧のとおり、bcabの通常の前提条件ですが、yzxおよびyの注文のみの前提条件です。きれいな状態から始めて、それらは同じように見えます:

:~$ make a
touch c
touch b
touch a
:~$ make x
touch z
touch y
touch x
:~$ make a
make: `a' is up to date.
:~$ make x
make: `x' is up to date.

ただし、チェーンの最後(cz)で前提条件を手動で「更新」すると、違いがわかります。

:~$ touch c
:~$ make a
touch b
touch a
:~$ touch z
:~$ make x
make: `x' is up to date.

これは、存在する順序のみの前提条件が、タイムスタンプに関係なく、ターゲットを無効にしないことを示しています。ただし、注文のみのターゲットを削除すると、再構築されます(ただし、欠落しているファイルの再構築のみ)。

:~$ rm c
:~$ make a
touch c
touch b
touch a
:~$ rm z
:~$ make x
touch z

そうは言っても、レシピが実行される順序を変更する正しい方法は、ターゲット間の依存関係を修正することです。たとえば、mefirstaの前にビルドする場合は、次のようにmefirstaの前提条件にする必要があります。

a: mefirst
    @echo a

レシピが実行されると予想される順序を詳細に説明しなかったため、質問に完全な解決策を与えることはできません。


あなたの答えへの近道があります。それは解決策ではありませんが、それでも知っておくと面白いです。文書化されていませんが、単一のターゲットの前提条件は、表示されている順序で処理されているようです。 |記号はそれを変更しません。単純なケースでは、それを利用して、探している出力を実現できます。

normaltarget: mefirst2 normaltarget2
    @echo "normaltarget done"

そして

helloworld: mefirst normaltarget
    @echo "helloworld done"

ただし、ご自身で指摘されているように、この「ソリューション」は、-jフラグを使用してレシピを並行して実行するとすぐに機能しなくなります。また、ユーザーbobbogoが指摘しているように、この順序付けメカニズムに依存することは悪い習慣です。新しい依存関係を導入すると、順序が妨げられる可能性があります。だからこれをしないでください:-)

44