web-dev-qa-db-ja.com

トップターゲットが作成されたときに依存関係を無視するように「make」に指示する

私は次の種類のパイプラインを実行しています:

digestA: hugefileB hugefileC
    cat $^ > $@
    rm $^

hugefileB:
    touch $@

hugefileC:
    touch $@

ターゲットhugefileBおよびhugefileCは非常に大きく、計算に長い時間がかかります(そして、Makeの能力が必要です)。ただし、digestAが作成されると、その依存関係を保持する必要はありません。それらの依存関係を削除して、ディスク領域を解放します。

ここで、「make」を再度呼び出すと、hugefileBおよびhugefileCが再構築されますが、digestAはすでに問題ありません。

依存関係の再コンパイルを回避するように「make」に指示する方法はありますか?

注:「digestA」のルール内に2つの依存関係を構築したくありません。

23
Pierre

使用 "中間ファイル" 機能GNU作成:

中間ファイルは、他のすべてのファイルと同じように、ルールを使用して再作成されます。ただし、中間ファイルは2つの方法で異なる方法で処理されます。

最初の違いは、中間ファイルが存在しない場合に何が起こるかです。通常のファイルbが存在せず、makeがbに依存するターゲットを考慮する場合、makeは常にbを作成し、bからターゲットを更新します。 しかし、bが中間ファイルの場合、makeは十分にそのままにしておくことができます。 bの前提条件がそのターゲットよりも新しいか、そのターゲットを更新する他の理由がない限り、bまたは最終的なターゲットを更新する必要はありません。

2つ目の違いは、makeが他の何かを更新するためにbを作成した場合、bは不要になった後で削除することです。 したがって、makeの前に存在しなかった中間ファイルは、makeの後にも存在しません。makeは、rm -fを出力して削除を報告します。削除するファイルを表示するコマンド。

通常、ファイルがターゲットまたは前提条件としてmakefileで言及されている場合、ファイルを中間にすることはできません。 ただし、ファイルを特別なターゲットの前提条件としてリストすることにより、ファイルを中間として明示的にマークすることができます.INTERMEDIATEこれは、ファイルは他の方法で明示的に言及されています。

中間ファイルをセカンダリファイルとしてマークすることで、自動削除を防ぐことができます。これを行うには、特別なターゲットの前提条件としてリストします.SECONDARY。ファイルがセカンダリの場合、makeはファイルがまだ存在しないという理由だけでファイルを作成しませんが、makeはファイルを自動的に削除しません。ファイルをセカンダリとしてマークすると、そのファイルも中間としてマークされます。

したがって、Makefileに次の行を追加するだけで十分です。

.INTERMEDIATE : hugefileB hugefileC

初めてmakeを呼び出す:

$ make
touch hugefileB
touch hugefileC
cat hugefileB hugefileC > digestA
rm hugefileB hugefileC

そして次回:

$ make
make: `digestA' is up to date.
30

hugefileBhugefileC中間ファイル としてマークすると、次のような動作が得られます。

digestA: hugefileB hugefileC
        cat $^ > $@

hugefileB:
        touch $@

hugefileC:
        touch $@

.INTERMEDIATE: hugefileB hugefileC

例えば:

$ gmake
touch hugefileB
touch hugefileC
cat hugefileB hugefileC > digestA
rm hugefileB hugefileC
$ gmake
gmake: `digestA' is up to date.
$ rm -f digestA
$ gmake
touch hugefileB
touch hugefileC
cat hugefileB hugefileC > digestA
rm hugefileB hugefileC

明示的なrm $^コマンドはもう必要ないことに注意してください。gmakeは、ビルドの最後に中間ファイルを自動的に削除します。

3
Eric Melski

hugefileBおよびhugeFileCターゲットによって作成される疑似キャッシュファイルを作成することをお勧めします。

次に、digestAをこれらのキャッシュファイルに依存させます。これは、高価なターゲットを手動で呼び出すまで、キャッシュファイルが再び変更されないことがわかっているためです。

1
SirDarius

参照 。PRECIOUS

.PRECIOUS : hugefileA hugefileB

.PRECIOUS

.PRECIOUSが依存するターゲットには、次の特別な処理が与えられます。レシピの実行中にmakeが強制終了または中断された場合、ターゲットは削除されません。 makeの中断または強制終了を参照してください。また、ターゲットが中間ファイルの場合、通常行われているように、不要になった後は削除されません。暗黙のルールのチェーンを参照してください。この後者の点では、.SECONDARY特別なターゲットと重複しています。

暗黙的なルールのターゲットパターン(「%.o」など)を特別なターゲット.PRECIOUSの前提条件ファイルとしてリストして、ターゲットパターンがそのファイルの名前と一致するルールによって作成された中間ファイルを保持することもできます。

編集:質問を読み直すと、hugefilesを保持したくないことがわかりました。多分これを行う:

digestA : hugefileA hugefileB
    grep '^Subject:' %^ > $@
    for n in $^; do echo > $$n; done
    sleep 1; touch $@

使用後にhugefileを切り捨て、1秒後に出力ファイルにアクセスして、出力が入力よりも新しく、空のhugefileが削除されるまでこのルールが再度実行されないようにします。

残念ながら、ダイジェストのみが削除された場合、このルールを実行すると空のダイジェストが作成されます。それをブロックするコードを追加することをお勧めします。

0
PFudd