24

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

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

hugefileB:
    touch $@

hugefileC:
    touch $@

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

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

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

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

4

5 に答える 5

32

GNU Make の「中間ファイル」機能を使用します。

中間ファイルは、他のすべてのファイルと同様に、ルールを使用して再作成されます。ただし、中間ファイルの扱いは 2 つの点で異なります。

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

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

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

中間ファイルを 2 次ファイルとしてマークすることにより、中間ファイルの自動削除を防ぐことができます。これを行うには、それを特別なターゲットの前提条件としてリストし.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.
于 2012-08-30T15:03:58.370 に答える
3

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 は、ビルドの最後に中間ファイルを自動的に削除します。

于 2012-08-30T15:04:36.407 に答える
1

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

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

于 2012-08-30T14:40:13.587 に答える
0

.PRECIOUSも参照してください。

.PRECIOUS : hugefileA hugefileB

。貴重

.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 が削除されるまでこのルールが再度実行されないようにするためです。

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

于 2020-01-06T18:40:03.997 に答える
-2

正しい方法は、ファイルを削除しないことです。削除すると、ファイルmakeを再構築するかどうかを決定するために使用する情報が削除されます。

それらを空として再make作成しても、空のファイルが完全に構築されたと想定されるため、役に立ちません。

ダイジェストをマージする方法がある場合は、巨大なファイルのそれぞれから 1 つを作成して保持し、巨大なファイルは中間であるため自動的に削除されます。

于 2012-08-30T14:46:50.637 に答える