16

テストを実行するための少しハックなmakefileがあります。

### Run the tests

tests := tests/test1 tests/test2 ...

test: $(tests)

$(tests): %: %.c
    gcc -o $@ $(testflags) $<
    $@

それは機能しますが、Makeに今まで見たことのないことをさせます。私のテストは現在壊れており、バスエラーが発生します。Makeは次の出力を提供します。

gcc -o tests/test1 [flags blah blah] tests/test1.c
tests/test1
make: *** [tests/test1] Bus error
make: *** Deleting file `tests/test1'

最後の行が気になります。Makeがそれをするのを見たことがありません。Makeがコンパイルされたテストを削除するのはなぜですか?

注:この例は、簡単にするためにかなり大幅に編集しました。私はいくつかの間違いを導入したかもしれません。

4

3 に答える 3

18

ターゲットが正しく構築されていない可能性があるためです。次回makeプロジェクトを実行すると、ターゲットの再構築が試行されます。ファイルが削除されていなかった場合、make何かがうまくいかなかったことを知る方法はありません。 make失敗がターゲットを構築するプロセスではなく、テストから発生したことを知ることはできません。


この動作があなたのケースで望ましいかどうかは、テストの性質によって異なります。を引き起こさないようにテストを修正することを計画している場合Bus error、ターゲットを削除することは大したことではありません。後でデバッグするためにターゲットを使用する場合は、makeプロセスに変更を加える必要があります。

ターゲットを削除しない1つの方法は、.PRECIOUSターゲットを使用することです。


別の可能性があります:

$(tests): %: %.c
    gcc -o $@ $(testflags) $<
    -$@

テストされていませんが、ドキュメントにはターゲットが削除されないことが示されています。

makeが無視するように指示されていないというエラーが発生した場合、それは現在のターゲットを正しくリメイクできないことを意味し、直接的または間接的にそれに依存する他のターゲットもリメイクできません。これらのターゲットは前提条件が満たされていないため、これ以上コマンドは実行されません。

と:

通常、コマンドが失敗したときに、ターゲットファイルを変更した場合、ファイルは破損して使用できません。または、少なくとも完全には更新されていません。ただし、ファイルのタイムスタンプには、ファイルが最新であることが示されているため、次回makeを実行するときに、そのファイルを更新しようとはしません。状況は、コマンドがシグナルによって強制終了された場合とまったく同じです。割り込みを参照してください。したがって、一般的に正しいことは、ファイルの変更を開始した後にコマンドが失敗した場合にターゲットファイルを削除することです。.DELETE_ON_ERRORがターゲットとして表示される場合、makeはこれを実行します。これはほとんどの場合、あなたがやりたいことですが、歴史的な慣習ではありません。したがって、互換性のために、明示的に要求する必要があります。

于 2009-02-26T00:23:18.640 に答える
14

この動作を回避する1つの方法は、ビルドとテストの実行を2つのステップに分割することです。

tests := tests/test1 tests/test2 ...

test: $(tests) runtests

$(tests): %: %.c
    gcc -o $@ $(testflags) $<

runtests: %.out: %
    $< | tee $@

(私のmake構文にはおそらくエラーがあります。誰でも自由に修正できます。)一般的な考え方は、テストを実行して出力ファイルを生成することです。これにより、make各テストを個別に実行しやすくなります。

于 2009-02-26T00:24:45.643 に答える
6

これは make のデフォルトの動作です。コマンドがエラー コード (ゼロ以外のリターンなど) を返すと、make ターゲットは削除されます。.PRECIOUS および .IGNORE メイクファイル ディレクティブは、この動作を変更できます。

于 2009-02-26T00:33:58.117 に答える