直接在目标依赖项中定义“如果出错则继续”策略

nor*_*bjd 5 makefile gnu-make

a这是一个带有 4 个目标( 、bc)的简单 Makefile all。目标b可能会失败(此处用 表示exit 1)。

a:
    echo "a"

b:
    exit 1

c:
    echo "c"

all: a b c
Run Code Online (Sandbox Code Playgroud)

运行时make allc永远不会打印为b失败,c因此目标不会运行。但就我的具体情况而言,c即使b失败,我也想继续竞选。

我想知道是否有一种方法可以直接在 target 的依赖项中定义“如果出现错误则继续”策略all

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

  • 运行make -i all( --ignore-errors) 或make -k all( --keep-going)
  • 使用“递归”make
  • 在失败的命令前添加前缀b--exit 1
  • 分别运行任务make a; make b || make c

但所有这些选项都意味着修改目标ab或者修改调用c方式。make all

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

附加要求:如果失败,即使目标成功,也make all应返回退出代码 1 。bc

Ren*_*let 4

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

a c:
    @echo "$@"

b:
    @echo "$@"; exit 1

all: a -b c

-%:
    -@$(MAKE) $*
Run Code Online (Sandbox Code Playgroud)

演示(用于--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
Run Code Online (Sandbox Code Playgroud)

但如果你还想“记住”他们的退出状态,事情就有点困难了。我们需要将退出状态存储在某个地方,例如在文件中,并将其重新用于配方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
Run Code Online (Sandbox Code Playgroud)

演示:

$ 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
Run Code Online (Sandbox Code Playgroud)

在配方中硬连接潜在失败目标的名称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
Run Code Online (Sandbox Code Playgroud)

演示:

$ 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
Run Code Online (Sandbox Code Playgroud)