为什么GNU会删除文件

时间:2009-02-26 00:21:57

标签: makefile gnu-make

我有一个稍微讨厌的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删除已编译的测试?

注意:我非常重视这个例子以使其更简单。我可能会介绍一些错误。

3 个答案:

答案 0 :(得分:14)

因为目标可能未正确构建。下次make项目时,它将尝试重建目标。如果文件尚未删除,make将无法知道出现问题。 make无法知道失败来自测试,而不是来自构建目标的过程。


在您的情况下,这种行为是否合适取决于测试的性质。如果您计划修复测试以使其不会导致Bus error,则删除目标并不是什么大问题。如果您想稍后使用目标进行调试,则需要对make过程进行更改。

不删除目标的一种方法是使用.PRECIOUS目标。


另一个可能是:

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

未经测试,但documentation表示目标不会被删除:

  

当一个错误发生时,make没有被告知忽略,这意味着当前目标无法正确重建,也不能直接或间接地依赖它。不会为这些目标执行进一步的命令,因为它们的先决条件尚未实现。

  

通常,当命令失败时,如果它完全更改了目标文件,则该文件已损坏且无法使用 - 或者至少未完全更新。然而文件的时间戳表示它现在是最新的,所以下次make运行时,它不会尝试更新该文件。情况与命令被信号杀死时的情况相同;看到中断。因此,通常正确的做法是在开始更改文件后如果命令失败则删除目标文件。如果.DELETE_ON_ERROR作为目标出现,make将执行此操作。这几乎总是你想要做的事情,但这不是历史实践;因此,为了兼容性,您必须明确请求它。

答案 1 :(得分:11)

避免此行为的一种方法是将构建和测试执行分为两个步骤:

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

test: $(tests) runtests

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

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

(我的make语法可能存在错误,任何人都可以随意纠正它。)一般的想法是让测试运行生成一个输出文件,这使make更容易单独运行每个测试。

答案 2 :(得分:6)

这是make的默认行为。 当命令返回错误代码(例如非零返回)时,则删除make目标。 .PRECIOUS和.IGNORE makefile指令可以改变这种行为。