我有一个稍微hackish 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删除已编译的测试?
注意:我非常重视这个例子以使其更简单.我可能会介绍一些错误.
因为目标可能没有正确构建.下次您执行make
该项目时,它将尝试重建目标.如果文件没有删除,make
就无法知道出了什么问题. make
无法知道失败来自测试而不是构建目标的过程.
在您的情况下,这种行为是否合适取决于测试的性质.如果您计划修复测试以使其不会导致测试,那么Bus error
移除目标并不是什么大问题.如果您希望稍后使用目标进行调试,则需要对make进程进行更改.
不删除目标的一种方法是使用.PRECIOUS
目标.
另一个可能是:
$(tests): %: %.c gcc -o $@ $(testflags) $< -$@
未经测试,但文档表明目标不会被删除:
当一个错误发生时,make没有被告知忽略,这意味着当前目标无法正确重新制作,也不能直接或间接地依赖它.不会对这些目标执行进一步的命令,因为它们的先决条件尚未实现.
和:
通常,当命令失败时,如果它完全更改了目标文件,则该文件已损坏且无法使用 - 或者至少未完全更新.然而文件的时间戳表示它现在是最新的,所以下次make运行时,它不会尝试更新该文件.情况与命令被信号杀死时的情况相同; 看到中断.因此,通常正确的做法是在开始更改文件后如果命令失败则删除目标文件.如果.DELETE_ON_ERROR作为目标出现,make将执行此操作.这几乎总是你想要做的事情,但这不是历史实践; 因此,为了兼容性,您必须明确请求它.
避免此行为的一种方法是将构建和测试执行分为两个步骤:
tests := tests/test1 tests/test2 ... test: $(tests) runtests $(tests): %: %.c gcc -o $@ $(testflags) $< runtests: %.out: % $< | tee $@
(我的make语法可能存在错误,任何人都可以随意纠正它.)一般的想法是让测试运行生成一个输出文件,这样可以更容易make
地单独运行每个测试.
这是make的默认行为.当命令返回错误代码(例如非零返回)时,将删除make目标..PRECIOUS和.IGNORE makefile指令可以更改此行为.