如何从make中的管道中的第一个命令获取退出状态?

时间:2014-03-12 17:03:04

标签: windows pipe gnu-make exit-code tee

我正在尝试将编译器的输出传递给windows中的tee命令,但是我遇到了一个问题,如果编译器在内部失败,它会在我想要它时继续编译下一个文件停止。有没有办法让第一个命令的退出状态成为第二个命令的退出状态?

$(ODIR)/%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS) 2>&1 | tee build_log.txt

3 个答案:

答案 0 :(得分:0)

首先,我会将任何记录留给make的调用者。第二关,这种管道在制作上是不整齐的。第三,不是失去 make里面的stderr流的粉丝。

那就是说,这是一个shell问题。如果您使用的是bash,请参阅手册中的 pipefail 。不幸的是,我觉得开启相当棘手。 (是的,我知道你说过窗户,但我认为你并没有使用可执行的 cmd 。)

SHELL := /bin/bash

passes:
    (exit 1) |& cat

fails:
    bash -c 'set -o pipefail; (exit 1) |& cat'

答案 1 :(得分:0)

经过苦苦挣扎,我来到了这个解决方案......

.ONESHELL:
$(ODIR)/%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS) 2> temp_err_file
    set EXIT_STATUS=%ERRORLEVEL%
    type temp_err_file >> build_log.txt
    type temp_err_file 1>&2
    del /q temp_err_file
    exit /b %EXIT_STATUS%

这里.ONESHELL允许make在单个shell命令中运行整个配方,而不是在单独的cmd中运行每一行,并分别收集每个命令的返回状态。总体退出状态取决于主编译命令,因此最终必须以编译状态退出。

我知道它不是一个涉及temp_err_file的干净解决方案,如果在编译命令之后出现问题,make将无法捕获它,但我认为这是我能找到的最好的工作窗口而不会丢失stderr流和日志记录。

答案 2 :(得分:0)

以下是与外壳无关的方法,在某些情况下可行:

假设您有一个食谱:

target:
        try_making_target |& tee target.log

我所做的就是将其转换为:

target:
        (try_making_target || rm -f $@) |& tee target.log
        test -e $@

管道命令失败,“回退”(||之后的命令)将删除目标文件,最终测试将失败。请注意,此示例假定操作系统为Linux(删除时为“ rm”),并且您的外壳程序支持||。运算符。

这假定 try_making_target 失败时,您对部分结果不感兴趣。如果要将部分结果保留在“目标”中,则可以使用其他“标记”文件来指定 try_making_target 的成功或失败。这样的事情可能会起作用:

target:
        touch $@.succeeded                                          # Assume success
        (try_making_target || rm -f $@.succeeded) |& tee target.log # Delete to mark failure
        test -e $@.succeeded                                        # Fail if marker
        rm $@.succeeded                                             # Remove unneeded marker

最后一个代码也适用于虚假目标,尽管您确实应该尽量减少使用它们(我尝试仅将它们用作实际文件的助记符,这些文件的名称可能很长)。