直接在目标依赖项中定义“错误时继续”策略

时间:2018-12-13 10:50:55

标签: makefile gnu-make

这是一个简单的Makefile,具有4个目标(abcall)。目标b可能会失败(此处用exit 1表示)。

a:
    echo "a"

b:
    exit 1

c:
    echo "c"

all: a b c

运行make all时,c不会打印,因为b会失败,因此目标c不会运行。但是在我的情况下,即使c失败,我也希望运行b

我想知道是否有一种方法可以在目标all的依赖项中直接直接定义“继续执行错误”策略。

我知道可以通过以下方式达到所需的行为:

  • 运行make -i all--ignore-errors)或make -k all--keep-going
  • 使用"recursive" make
  • b中用-前缀失败的命令(例如-exit 1
  • 使用make a; make b || make c单独运行任务

但是所有这些选项都意味着要修改目标abc,或修改make all的调用方式。

是否有一种方法可以通过仅修改 all目标依赖项(类似于all: a -b c,但是显然该定义不起作用)来实现预期的行为?< / p>

其他要求:即使make all目标成功,b也应以退出代码1返回,如果c失败。

2 个答案:

答案 0 :(得分:2)

如果您要运行a, -b, c的所有配方,即使-<something>的配方失败,则可以对-<something>目标使用模式规则:

a c:
    @echo "$@"

b:
    @echo "$@"; exit 1

all: a -b c

-%:
    -@$(MAKE) $*

演示(使用--no-print-directory可以简化输出):

$ make --no-print-directory all
a
b
Makefile:5: recipe for target 'b' failed
make[1]: *** [b] Error 1
Makefile:10: recipe for target '-b' failed
make: [-b] Error 2 (ignored)
c

但是,如果您还想“记住”它们的退出状态,则事情会有些困难。我们需要将退出状态存储在某个地方,例如存储在文件中,并将其重新用于all配方:

a c:
    @echo "$@"

b:
    @echo "$@"; exit 1

all: a -b c
    @exit_status=`cat b_exit_status`; exit $$exit_status

-%:
    -@$(MAKE) $*; echo "$$?" > $*_exit_status

演示:

$ make --no-print-directory all
a
b
Makefile:5: recipe for target 'b' failed
make[1]: *** [b] Error 1
c
Makefile:8: recipe for target 'all' failed
make: *** [all] Error 2

all的配方中硬接线可能失败目标的名称不是很优雅。但这应该很容易解决:

a b c:
    @echo "$@"

d:
    @echo "$@"; exit 1

all: a -b c -d
    @for f in $(patsubst -%,%_exit_status,$(filter -%,$^)); do \
        tmp=`cat $$f`; \
        printf '%s: %s\n' "$$f" "$$tmp"; \
        if [ "$$tmp" -ne 0 ]; then exit $$tmp; fi; \
    done

-%:
    -@$(MAKE) $*; echo "$$?" > $*_exit_status

.PHONY: clean
clean:
    rm -f *_exit_status

演示:

$ make --no-print-directory all
a
b
c
d
Makefile:5: recipe for target 'd' failed
make[1]: *** [d] Error 1
b_exit_status: 0
d_exit_status: 2
Makefile:8: recipe for target 'all' failed
make: *** [all] Error 2

答案 1 :(得分:0)

虽然您不能通过先决条件名称(或至少仅在完全更改先决条件时)来传递参数,但是可以使用特定于目标的变量。但是解决方案并不完美,在每个配方行前都有一个附加变量:

CIE_DASH = $(if $(filter $@,$(CONTINUE_SET)),-)

all: a b c
all: CONTINUE_SET += b

a: 
    $(CIE_DASH)echo "a"

b: CONTINUE_SET += e
b: e 
    $(CIE_DASH)exit 1

e:
    $(CIE_DASH)exit 1
c:
    $(CIE_DASH)echo "c"