【问题标题】:How do I get a makefile function to stop the current target?如何获得一个 makefile 函数来停止当前目标?
【发布时间】:2017-10-18 18:24:45
【问题描述】:

我在 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

我希望它在函数中,因为大多数目标不调用该函数(这显然会执行更多 IRL)。

我该如何进行这项工作?

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    先说几件事:

    .PHONY=a
    

    什么都不做:变量.PHONY 并不特殊。要声明一个虚假目标,您需要将其列为.PHONY 伪目标的先决条件:

    .PHONY: a
    

    第二,这一行:

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

    什么都不做:这里没有设置make变量$(1),所以test总是失败,但这没关系,因为退出代码被忽略了,见下文。

    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 函数,该函数会立即停止 make,并打印该错误消息。

    【讨论】:

      【解决方案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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多