在Makefile中,如果其他目标已过期(或在依赖项之前运行配方),则运行虚拟目标(第一个)

时间:2016-10-17 19:10:26

标签: makefile gnu-make

(使用GNU make)

我有Makefile默认目标负责“编译”代码。我没有run_test目标执行测试,但会在需要时重新编译。

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

  1. make all当所有都是最新的 - 没有运行,日志未清除
  2. make all最新时 - 日志已清除,然后运行相应的编译规则
  3. make run_test当所有都是最新的 - 没有编译,日志未清除,测试运行
  4. make run_test最新时 - 清除日志,然后运行适当的编译规则,然后运行测试
  5. 如何在必须进行编译时,但在任何依赖关系配方运行之前,才能使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_log是一个final.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
    

1 个答案:

答案 0 :(得分:1)

使用第二个临时日志文件

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