如果目标失败,Makefile应该出故障

时间:2019-04-23 08:07:29

标签: bash makefile grep

我有以下格式的制作文件-

all: target_1 target_2 target_3

target_1:
    TASK_A1 | tee ta.log
    TASK_A2 | tee -a ta.log

target_2:
    TASK_B | tee tb.log

target_3:
    TASK_C | tee tc.log

TASK_A以此格式生成日志记录输出-

<some lines of output>
Errors: 0, Warnings: 12
<some more lines of output>
Errors: 5, Warnings: 10

当我执行全部制作时,理想情况下,如果target_1失败,但makefile仍应恢复到target_2,

我想到的一种可能的解决方案是从每个目标中的日志文件中grep“ Errors:0”,然后检查grep的返回值(如果grep返回非零值,则退出)。我发现这并不是一个非常有效的解决方案,因为我需要针对每个目标执行上述步骤。

有没有更有效,更智能的方法来解决此问题?

2 个答案:

答案 0 :(得分:1)

不了解任何单个任务,除了处理“错误:0”的输出外,您无能为力。但是,您可以像下面这样应用DRY原理:

runtask = $(1) | tee -a $(2) | awk '{ print; if (/Errors: 0/) y=1; } END { if (y) { exit 0 } else { exit 1 } }'

all: target_1 target_2 target_3

target_1:
        @$(call runtask, TASK_A1, ta.log)
        @$(call runtask, TASK_A2, ta.log)

target_2:
        @$(call runtask, TASK_B, tb.log)

target_3:
        @$(call runtask, TASK_C, tc.log)

至少,如果您需要修改搜索模式,则不必遍历每一行。

答案 1 :(得分:0)

因此,首先,如果target_2依赖于target_1,则应在makefile中明确指定它:

target_2: target_1

否则,如果有人使用-j进行构建,那么无论target_2是否成功,target_1都可能会运行。

接下来,如果一个目标失败,您希望make失败。如果配方行的返回为假(非零),则Make将终止。我假设TASK_A1和朋友如果生成错误,则返回false(否则,本篇文章的其余部分将是空白)。

不幸的是,您有一个使事情复杂化的管道-即,配方的返回值将是tee而不是TASK_A1的返回值。见下文:

bash> false
bash> echo $?
1
bash> false | tee blah
bash> echo $?
0

在这种情况下,tee blah返回了真(0),因此$?(返回码)为0。幸运的是,您可以使用PIPESTATUS来获取返回值管道第一部分的代码。

bash> false | tee blah; [ ${PIPESTATUS[0]} -eq 0 ]
bash> echo $?
1
bash> true | tee blah; [ ${PIPESTATUS[0]} -eq 0 ]
bash> echo $?
0

所以...总之,您可以执行以下操作:

all: target_3

target_1: 
    TASK_A1 | tee ta.log; [ $${PIPESTATUS[0]} -eq 0 ]
    TASK_A2 | tee -a ta.log; [ $${PIPESTATUS[0]} -eq 0 ]

target_2: target1
    TASK_B | tee tb.log; [ $${PIPESTATUS[0]} -eq 0 ]

target_3: target2
    TASK_C | tee tc.log; [ $${PIPESTATUS[0]} -eq 0 ]

一旦make遇到失败的任务,它将失败。 请注意,在此解决方案中,如果TASK_A1失败,则TASK_A2将不会运行。我不确定这是否是您想要的。如果您希望两者都运行,则可以将target1更改为:

target1:
   ( TASK_A1; TASK_A2 ) | tee ta.log; [ $${PIPESTATUS[0]} -eq 0 ]