我正在尝试将编译器的输出传递给windows中的tee命令,但是我遇到了一个问题,如果编译器在内部失败,它会在我想要它时继续编译下一个文件停止。有没有办法让第一个命令的退出状态成为第二个命令的退出状态?
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS) 2>&1 | tee build_log.txt
答案 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
最后一个代码也适用于虚假目标,尽管您确实应该尽量减少使用它们(我尝试仅将它们用作实际文件的助记符,这些文件的名称可能很长)。