我有以下格式的制作文件-
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返回非零值,则退出)。我发现这并不是一个非常有效的解决方案,因为我需要针对每个目标执行上述步骤。
有没有更有效,更智能的方法来解决此问题?
答案 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 ]