如何让makefile函数停止当前目标?

3

我在一个makefile中有一个函数,如果文件不存在,或者至少从执行的目标中不存在,我想停止整个make运行:

vaultfile = ./vault

$(shell test -f $(1) || exit 1)

define get_token
$(shell test -f $1 && cat $1 || exit 2)
endef

a: token = $(call get_token,$(vaultfile),tokenname)
a:
        echo ==== $(token)
.PHONY=a

上述方法无法实现,在文件缺失时不会有任何提示。
$ rm vault
$ make
echo ==== 
====
$ echo f > vault
$ make
echo ==== f
==== f

我希望这个功能能够实现,因为大多数目标并不调用该功能(在现实中显然做更多的事情)。

我该如何让它工作?

2个回答

2

感谢MadScientist

我最终得到的简化版本是:(为了更易读,进行了格式化)

vaultfile = ./vault

define get_token
$(shell \
$(if $(wildcard $1), \
echo "Decoded $1" \
, \
$(error File $1 does not exist)
)
)
endef

a: token = $(call get_token,$(vaultfile))
a:
        echo ==== $(token)

2

首先需要说明的几点:

.PHONY=a

没有任何作用:变量.PHONY对于make来说并不是特殊的。要声明一个虚拟目标,您需要将其列为.PHONY伪目标的先决条件:

.PHONY: a

第二,这一行代码:
$(shell test -f $(1) || exit 1)

不起作用:在此处未设置make变量$(1),因此测试始终失败,但这并不重要,因为退出代码被忽略,请参见下面的内容。
来自make shell函数的退出代码不会导致make失败,它会被忽略。要使make认为配方失败,必须使命令行本身以非零值退出。
一个很好的经验法则是,如果你发现自己在配方中使用make shell函数,那么你正在做错事情,并且你没有理解make如何扩展变量和函数。一个配方已经将被传递给shell,因此你根本不需要使用shell函数。
让我们看看在第一步扩展后,对于token变量,你的配方将是什么样子:
    echo ==== $(call get_token,$(vaultfile),tokenname)

现在,当call函数被扩展后(请注意,函数的第二个参数tokenname完全被忽略),你会得到以下结果:
    echo ==== $(shell test -f ./vault && cat ./vault || exit 2)

现在,make扩展了shell函数,该函数调用shell以运行命令并使用输出替换扩展...但忽略退出代码。假设./vault不存在:那么此shell命令不会输出任何内容,并且make将运行此规则:
    echo ==== 

停止整个 make 运行的最佳方法是使用 error 函数。您可以使用 make 函数来完成所有工作,如下所示:

vaultfile = ./vault

get_token = $(if $(wildcard $1),`cat $1`,$(error File $1 does not exist))

a: token = $(call get_token,$(vaultfile),tokenname)
a:
        echo ==== $(token)

让我们来看一下现在调用扩展的结果:call
    echo ==== $(if $(wildcard ,/vault),`cat ./vault`,$(error File ./vault does not exist))

现在,make评估if函数,条件是wildcard函数,如果存在,则会扩展为./vault,否则为空字符串。 if函数将非空字符串视为“true”,空字符串视为“false”,因此如果文件存在,则会扩展为:
    echo ==== `cat ./vault`

如果文件不存在,它将运行error函数,该函数会立即停止执行并打印错误消息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接