Bash 如果目标失败,Makefile应该退出
我有一个以下格式的makefile-Bash 如果目标失败,Makefile应该退出,bash,makefile,grep,Bash,Makefile,Grep,我有一个以下格式的makefile- 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 <some lines of output> Errors: 0, Warnings: 12 <some mo
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
<some lines of output>
Errors: 0, Warnings: 12
<some more lines of output>
Errors: 5, Warnings: 10
任务_A生成以下格式的日志输出-
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
<some lines of output>
Errors: 0, Warnings: 12
<some more lines of output>
Errors: 5, Warnings: 10
错误:0,警告:12
错误:5,警告:10
当我完成全部生成时,理想情况下,如果目标_1失败,但它继续以目标_2为目标,makefile应该退出
我能想到的一个可能的解决方案是从每个目标的日志文件中grep“Errors:0”,然后检查grep的返回值(如果grep返回非零值,则退出)。我不认为这是非常有效的解决方案,因为我需要为每个目标执行上述步骤
是否有更有效、更智能的方法来解决此问题?不知道更多的单个任务,除了处理“错误:0”的输出之外,您无法做更多的事情。但是,您可以像这样应用干燥原理:
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)
至少这样,如果需要修改搜索模式,您不必遍历每一行。因此,首先,如果
target_2
依赖于target_1
,您应该在makefile中明确指定:
target_2: target_1
否则,如果有人使用-j
构建,则无论target\u 1
是否成功,target\u 2
都可能会运行
接下来,如果其中一个目标失败,您希望使其失败。如果配方行返回值为false(非零),Make将终止。我假设,TASK_A1
和friends如果产生错误,则返回false(否则本文的其余部分就没有意义了)
不幸的是,您有一个使事情复杂化的管道——即,配方的返回值将是tee
的返回值,而不是TASK\u A1
。见下文:
bash> false
bash> echo $?
1
bash> false | tee blah
bash> echo $?
0
在本例中,teeblah
返回true(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 ]
idk关于其余部分,但在awk
{print;if(/Errors:0/)y=1;}END{if(y){exit 0}否则{exit 1}
相当于{print}/Errors:0/{y=1}END{exit!y}
非常感谢。您的解决方案非常有效,比我处理问题的方式更好、更干净。