直接在目标依赖项中定义 "continue if error" 策略

Define "continue if error" policy directly in target dependencies

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

a:
    echo "a"

b:
    exit 1

c:
    echo "c"

all: a b c

当 运行ning make all 时,c 永远不会打印,因为 b 失败并且目标 c 因此不是 运行。但在我的特殊情况下,我希望 c 成为 运行,即使 b 失败。

我想知道是否有一种方法可以在目标 all.

的依赖项中直接 定义 "continue if error" 策略

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

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

有没有办法通过 修改 all 目标依赖项(类似于 all: a -b c,但该定义不起作用, 显然)?

附加要求:如果 b 失败,make all 应该 return 退出代码 1,即使 c 目标成功.

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

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"

如果你想 运行 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