在Makefile中,如果其他目标过期,首先运行一个虚拟目标(或者在依赖项之前运行recipe)



(使用GNU make)

我有一个Makefile与默认目标负责"编译"代码。我希望run_test目标执行测试,但如果需要,将重新编译。

我想在任何编译步骤运行之前清除日志文件,但是只有在编译步骤运行时才清除,所以如果只是测试运行则不清除。我定义了一个reset_log目标来清除日志。我想要的行为是:

  1. make all当所有更新时-没有运行,日志未清除
  2. make all不是时-日志被清除,然后运行适当的编译规则
  3. make run_test当全部更新时-没有编译,日志未清除,测试运行
  4. make run_test不是时-日志被清除,然后运行适当的编译规则,然后运行测试

如何使reset_log目标(或等效命令)仅在必须进行编译时运行,但在任何依赖关系配方运行之前运行?下面是简化的Makefile:

LOG_FILE = file.log
all: compile
compile: final.out
reset_log:
    -rm -f $(LOG_FILE)
final.out: final.in reset_log 1.out 2.out
    cp -v final.in final.out | tee -a $(LOG_FILE)
1.out: 1.in
    cp -v 1.in 1.out | tee -a $(LOG_FILE)
2.out: 2.in
    cp -v 2.in 2.out | tee -a $(LOG_FILE)
run_test: compile
    @echo "======= Run Test Here ======="

clean:
    -rm *.out $(LOG_FILE)
.PHONY: local_target reset_log run_test clean

注意:这个例子不工作 (reset_logfinal.out目标每次都重新运行,因为reset_logfinal.out的依赖项,本身没有依赖项),但演示了我想要运行reset_log的地方。

一种可能的解决方案是在依赖关系食谱运行之前为过期的目标运行食谱。


更新2016-10-18

基于user657267的解决方案(以及我在评论中建议的小改进),这里是上述示例的重新编码,即我需要的最终解决方案:

LOG = file.log
all: compile
compile: $(LOG)
$(LOG): final.out
    mv $@.tmp $@ || ( echo "WARNING: $< not found. Creating dummy $@ to allow make to run" > $@ )
final.out: 1.out 2.out
%.out: %.in
    cp -v $< $@ | tee -a $(LOG).tmp
run_test: compile
    @echo "======= Run Test Here ======="

clean:
    -rm *.out $(LOG)
.PHONY: run_test clean compile

使用第二个临时日志文件

log := file.log
out := final.out 1.out 2.out
.PHONY: run_test clean
$(log): $(out)
    mv $@.tmp $@
run_test: $(log)
    @echo "======= Run Test Here ======="
clean:
    $(RM) $(out) $(log)
%.out: %.in 
    cp -v $< $@ | tee -a $(log).tmp

最新更新