这是一个包含 4 个目标(a
、b
、c
和 all
)的简单 Makefile。目标 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
分别运行任务
但所有这些选项都意味着修改目标 a
, b
或 c
,或者修改方式make all
被称为。
有没有办法通过仅修改 all
来获得预期的行为?目标依赖项(类似于 all: a -b c
,但显然该定义不起作用)?
附加要求:make all
如果 b
应该返回退出代码 1失败,即使 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
关于makefile - 直接在目标依赖中定义 "continue if error"策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53760185/