Makefile 定义;如果出现错误,则继续“;直接在目标依赖项中使用策略
下面是一个简单的Makefile,它有4个目标(Makefile 定义;如果出现错误,则继续“;直接在目标依赖项中使用策略,makefile,gnu-make,Makefile,Gnu Make,下面是一个简单的Makefile,它有4个目标(a、b、c和all)。目标b可能失败(此处用退出1表示) 运行make all时,c永远不会打印,因为b失败,因此目标c不会运行。但在我的特殊情况下,我希望运行c,即使b失败 我想知道是否有一种方法可以直接在targetall的依赖项中定义“如果出错则继续”策略 我知道可以通过以下方式达到预期的行为: 运行make-i all(--忽略错误)或make-k all(--继续运行) 使用 在b中用-作为失败命令的前缀(如-退出1) 使用单独运行任务
a
、b
、c
和all
)。目标b
可能失败(此处用退出1
表示)
运行make all
时,c
永远不会打印,因为b
失败,因此目标c
不会运行。但在我的特殊情况下,我希望运行c
,即使b
失败
我想知道是否有一种方法可以直接在targetall
的依赖项中定义“如果出错则继续”策略
我知道可以通过以下方式达到预期的行为:
- 运行
(make-i all
)或--忽略错误
(make-k all
)--继续运行
- 使用
- 在
中用b
作为失败命令的前缀(如-
)-退出1
- 使用
单独运行任务,创建一个;做b | |做c
a
、b
或c
,或者修改调用make all
的方式
是否有一种方法可以通过修改all
目标依赖项(类似于all:a-bc
,但该定义显然不起作用)来实现预期行为
附加要求:
make all
如果b
失败,即使c
目标成功,也应返回退出代码1。虽然无法通过先决条件名称传输参数(或者至少只有在完全更改先决条件的情况下),但可以使用特定于目标的变量。但解决方案并不完美,每个配方行前面都有一个额外的变量:
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的所有配方,即使-
配方失败,也可以对-
目标使用模式规则:
a c:
@echo "$@"
b:
@echo "$@"; exit 1
all: a -b c
-%:
-@$(MAKE) $*
演示(使用--无打印目录
,输出更简单):
但如果你还想“记住”他们的退出状态,事情就有点困难了。我们需要将退出状态存储在某个位置,例如在一个文件中,并将其重新用于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
演示:
硬接线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
演示:
谢谢你的回答。在我的例子中,为什么exit 1
不是唯一应该以$(CIE_DASH)
作为前缀的行?因为只有b
目标才能失败。还有,为什么需要e
?最后,使用此解决方案,我如何捕获b
的退出代码并将其传播到c
(请参阅我问题中的附加要求)?我只需输入$(CIE_DASH)
出现在所有内容之前,因为您事先不知道某一天是否要将a
或c
添加到继续设置中<不需要代码>e
,我只是想证明这是一种抑制出错退出的分层方法-编写all
目标的程序员可能不知道b
下面发生的事情。传播到c
是不可能/不可靠的,因为make可以自由决定独立目标的求值顺序。正在传播到顶级规则。。。老实说,我认为这将变得更加丑陋,你不能使用我的解决方案,因为破折号强制忽略返回代码-无法访问它。谢谢你的解释。有了这个想法,它很聪明,在某些情况下可能有用。但在我解释的具体案例中,这个解决方案类似于我的第三点:在b
中用-
作为失败命令的前缀(如-exit 1
),因为我知道在我的示例中只有b
可以失败。因此,这里不需要使用CONTINUE\u SET
,也不需要使用CIE\u DASH
作为所有行的前缀。感谢您给出的详细解释。另一个问题(尽管不相关):如果我当前文件夹中有多个Makefile
,或者如果我必须将参数传递给Makefile
,我如何在$(MAKE)中指定这些参数
call?make-f VAR1=VALUE1 VAR2=VALUE2…
:-f
告诉make要使用的make文件是
,并且VAR1=VALUE1
用值VALUE1
定义make变量VAR1
。我的问题不清楚,对不起,事实上我已经在运行make-f VAR1=VALUE1=VALUE2
。但是在Makefile
中运行$(MAKE)
时,命令run是MAKE
,没有我用来运行初始MAKE
的参数。我想知道是否有一种简单的方法可以将这些参数传播到$(MAKE)
。这是一个非常不同的问题,很难在注释中回答。您可能应该问一个新问题。原始参数不会出现在运行sub make的命令行上。然而,潜艇制造商会知道他们。它们通过其他方式传递。(共享内存?环境变量?谁在乎……如果你在乎,请查看手册。)
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
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