Makefile:保存错误并在末尾打印

Makefile:保存错误并在末尾打印,makefile,gnu-make,Makefile,Gnu Make,我有以下Makefile snipt,它运行一些测试: MKFILES = $(wildcard $(addprefix $(UNIT_TEST_SRC)/,$(subst $(comma), ,*.mk)))) TESTS = $(MKFILES:.mk=.test) %.test:%.mk @make -f $? run_tests: $(TESTS) 上面的操作很好,但我正在尝试更改它,以便在测试出错时,它不会中止,而是继续并在最后打印出所有失败 FAILURES := %.

我有以下Makefile snipt,它运行一些测试:

MKFILES = $(wildcard $(addprefix $(UNIT_TEST_SRC)/,$(subst $(comma), ,*.mk))))
TESTS = $(MKFILES:.mk=.test)

%.test:%.mk
  @make -f $?

run_tests: $(TESTS)
上面的操作很好,但我正在尝试更改它,以便在测试出错时,它不会中止,而是继续并在最后打印出所有失败

FAILURES := 

%.test:%.mk
  @make -f $? || $(MAKE) $@.error

.PHONY: %.test.error
%.test.error:
  $(eval FAILURES += $@)

run_tests: $(TESTS)
   @echo "Failures:" $(FAILURES)
似乎我的
eval
%.test.error
范围内无法生存,如果我将
eval
移动到
%.test
中,它确实能够生存,尽管这不是我想要的


有办法做到这一点吗?

在以下规则的配方中:

%.test:%.mk
   @make -f $? || $(MAKE) $@.error
调用
make
,并创建另一个新的
make
运行实例。正是在这种情况下,
eval
才会发生。因此,它对执行上述配方的父
make
实例没有影响


相反,当发生错误时,您可以创建true
.test.error
文件:

%.test:%.mk
   @make -f $? || touch $@.error
完成后将其移除:

run_tests: $(TESTS)
   @echo "Failures:" $(FAILURES)
   @$(RM) *.test.error
故障的定义可以是:

FAILURE = $(wildcard *.test.error)
这样,当执行
run\u tests
recipe时,
FAILURE
将被展开(即:通过使用递归展开的变量进行延迟展开),因此它将包含
.test.error
文件(如果有)的列表。

当调用
$(MAKE)$@.error
,它将调用MAKE的新实例,而
功能
在那里设置。新值不会传播到父make

我可能建议使用临时文件/文件夹,如下所示:

.PHONY: prep
prep:
    rm -rf failures;
    mkdir failures;

%.test:%.mk: | prep
    @make -f $? || touch failures/$@.error

run_tests: $(TESTS)
    @echo "Failures:"
    @cd failures && ls || true
    @rm -rf failures

谢谢我想对于您来说,上一个列表的意思是:
FAILURES=$(通配符*.test.error)
这实际上会推迟初始化:您是多么正确!这是一个简单的扩展变量(
:=
),而递归扩展变量(
=
)就是所需要的。谢谢后续问题:当我执行类似于:
@echo”Failures:“$(Failures)
的操作时,它会按预期工作,但如果我执行类似于:
ifneq($(Failures),)$(error以下测试失败:$(Failures))endif
的操作,则
失败
似乎会在开始时进行评估,使用时不会。这是因为在解析makefile时会计算
ifneq
,因此
失败
也会在开始时展开。您可以创建一个额外的虚假空目标,例如:
检查错误
。然后在同一个makefile上递归调用该目标的
check errors
,但在命令行上传递
FAILURES
变量。即:
$(MAKE)check errors FAILURES=“$(FAILURES)”
。这样,第二次解析makefile时,
FAILURES
具有您在计算
ifneq
时希望它具有的值。