$(error ...)
如果不满足某些先决条件,我想用来中止我的制作过程.在fails_to_work
失败时,目标应该退出test -d /foobar
.
BAD.mk
all: this_works fails_to_work
this_works:
@echo echo works...
@test -d ~ || echo ~ is not a directory
@test -d /foobar || echo /foobar is not a directory
fails_to_work:
@echo error does not work...
@test -d ~ || $(error ~ is not a directory)
@test -d /foobar || $(error /foobar is not a directory)
Run Code Online (Sandbox Code Playgroud)
$ make -f BAD.mk
echo works...
/foobar is not a directory
BAD.mk:9: *** ~ is not a directory. Stop.
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,甚至"错误都不起作用......"也会回显到屏幕上.配方fails_to_work
在开始之前失败.我该如何解决这个问题?我的一个用例是@test -d $(MY_ENV_VAR)
,但我不认为这与示例中给出的硬编码路径不同.
更新(版本信息)
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for x86_64-pc-linux-gnu
Run Code Online (Sandbox Code Playgroud)
make配方的Shell命令有效地存储为单个递归扩展变量.在make决定运行配方时,它会扩展变量,然后在自己的shell调用中运行每一行.任何 $(error ...)
扩展的内容都会导致make 在调用第一个命令之前中止.
请注意a $(if ...)
或$(or ...)
&c 的未分支分支.不会扩大.因此,你可以这样做
.PHONY: rule-with-assert
rule-with-assert:
$(if $(realpath ${should-be-file}/),$(error Assertion failure: ${should-be-file} is a folder!))
?
Run Code Online (Sandbox Code Playgroud)
注意尾随/
中realpath
.
当然,宏有助于整理这一点.
assert-is-file = $(if $(realpath $1/),$(error Assertion failure: [$1] is a folder!))
.PHONY: rule-with-assert
rule-with-assert:
$(call assert-is-file,${should-be-file})
?
Run Code Online (Sandbox Code Playgroud)
值得注意的是,无论你把它放在$(call assert-is-file,…)
配方中的哪个位置都没关系.任何$(error)
在食谱膨胀,将会产生
之前任何外壳命令的前提.
你正试图在一个配方中获取shell的东西来有条件地调用makefile的东西,这是不行的,正如你所发现的那样.
我可以想到两个选择:
只需删除$(error)
东西.如果test
失败,则它将返回非零退出状态,并且Make过程将在该点终止.
从规则中取出测试,并使用Make条件(进而调用shell功能),例如:
ifeq ($(shell test -d /foobar; echo $$?),1)
$(error Not a directory)
endif
Run Code Online (Sandbox Code Playgroud)