如果未设置变量,则中止makefile [英] Abort makefile if variable not set

查看:179
本文介绍了如果未设置变量,则中止makefile的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何基于未设置/赋值makefile的变量来中止make/makefile执行?

How could I abort a make/makefile execution based on a makefile's variable not being set/valued?

我想到了这一点,但仅在调用者未明确运行目标(即仅运行make)时有效.

I came up with this, but works only if caller doesn't explicitly run a target (i.e. runs make only).

ifeq ($(MY_FLAG),)
abort:   ## This MUST be the first target :( ugly
    @echo Variable MY_FLAG not set && false
endif

all:
    @echo MY_FLAG=$(MY_FLAG)

我认为这样的想法是个好主意,但在make的手册中没找到任何内容:

I think something like this would be a good idea, but didn't find anything in make's manual:

ifndef MY_FLAG
.ABORT
endif

推荐答案

TL; DR :使用 error功能:

TL;DR: Use the error function:

ifndef MY_FLAG
$(error MY_FLAG is not set)
endif

请注意,行不能缩进.更准确地说,在这些行之前都不能使用任何制表符.

Note that the lines must not be indented. More precisely, no tabs must precede these lines.

如果要测试许多变量,则值得为其定义辅助功能:

In case you're going to test many variables, it's worth defining an auxiliary function for that:

# Check that given variables are set and all have non-empty values,
# die with an error otherwise.
#
# Params:
#   1. Variable name(s) to test.
#   2. (optional) Error message to print.
check_defined = \
    $(strip $(foreach 1,$1, \
        $(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
    $(if $(value $1),, \
      $(error Undefined $1$(if $2, ($2))))

这是如何使用它:

And here is how to use it:

$(call check_defined, MY_FLAG)

$(call check_defined, OUT_DIR, build directory)
$(call check_defined, BIN_DIR, where to put binary artifacts)
$(call check_defined, \
            LIB_INCLUDE_DIR \
            LIB_SOURCE_DIR, \
        library path)


这将输出如下错误:


This would output an error like this:

Makefile:17: *** Undefined OUT_DIR (build directory).  Stop.

注意:

真正的检查在这里完成:

Notes:

The real check is done here:

$(if $(value $1),,$(error ...))

这反映了ifndef条件的行为,因此将定义为空值的变量也视为未定义".但这仅适用于简单变量和明确为空的递归变量:

This reflects the behavior of the ifndef conditional, so that a variable defined to an empty value is also considered "undefined". But this is only true for simple variables and explicitly empty recursive variables:

# ifndef and check_defined consider these UNDEFINED:
explicitly_empty =
simple_empty := $(explicitly_empty)

# ifndef and check_defined consider it OK (defined):
recursive_empty = $(explicitly_empty)

如@VictorSergienko在评论中所建议,可能需要略有不同的行为:

As suggested by @VictorSergienko in the comments, a slightly different behavior may be desired:

$(if $(value $1)测试该值是否为非空.如果变量定义为空值,有时确定.我会用$(if $(filter undefined,$(origin $1)) ...

$(if $(value $1) tests if the value is non-empty. It's sometimes OK if the variable is defined with an empty value. I'd use $(if $(filter undefined,$(origin $1)) ...

并且:

此外,如果它是目录并且必须存在,则在运行检查时,我会使用$(if $(wildcard $1)).但这将是另一个功能.

Moreover, if it's a directory and it must exist when the check is run, I'd use $(if $(wildcard $1)). But would be another function.

针对特定目标的检查

还可以扩展解决方案,以便仅在调用特定目标时才需要变量.

Target-specific check

It is also possible to extend the solution so that one can require a variable only if a certain target is invoked.

只需将支票移到配方中:

Just move the check into the recipe:

foo :
    @:$(call check_defined, BAR, baz value)

前导@符号将关闭命令回显,而:是实际命令,即外壳

The leading @ sign turns off command echoing and : is the actual command, a shell no-op stub.

可以改进check_defined函数以输出目标名称(通过$@变量提供):

The check_defined function can be improved to also output the target name (provided through the $@ variable):

check_defined = \
    $(strip $(foreach 1,$1, \
        $(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
    $(if $(value $1),, \
        $(error Undefined $1$(if $2, ($2))$(if $(value @), \
                required by target `$@')))

因此,现在失败的检查会产生格式正确的输出:

So that, now a failed check produces a nicely formatted output:

Makefile:7: *** Undefined BAR (baz value) required by target `foo'.  Stop.

check-defined-MY_FLAG特殊目标

就我个人而言,我将使用上面简单而直接的解决方案.但是,例如,此答案建议使用特殊目标来执行实际操作查看.可以尝试将其概括化,然后将目标定义为隐式模式规则:

check-defined-MY_FLAG special target

Personally I would use the simple and straightforward solution above. However, for example, this answer suggests using a special target to perform the actual check. One could try to generalize that and define the target as an implicit pattern rule:

# Check that a variable specified through the stem is defined and has
# a non-empty value, die with an error otherwise.
#
#   %: The name of the variable to test.
#   
check-defined-% : __check_defined_FORCE
    @:$(call check_defined, $*, target-specific)

# Since pattern rules can't be listed as prerequisites of .PHONY,
# we use the old-school and hackish FORCE workaround.
# You could go without this, but otherwise a check can be missed
# in case a file named like `check-defined-...` exists in the root 
# directory, e.g. left by an accidental `make -t` invocation.
.PHONY : __check_defined_FORCE
__check_defined_FORCE :

用法:

foo :|check-defined-BAR

请注意,check-defined-BAR被列为仅订购(|...)先决条件.

Notice that the check-defined-BAR is listed as the order-only (|...) prerequisite.

优点:

  • (可以说)更简洁的语法

缺点:

  • 无法指定自定义错误消息
  • 运行make -t(请参见代替执行食谱)将使用许多check-defined-...文件污染您的根目录.这是一个令人遗憾的缺点,因为规则规则不能声明为.PHONY .
  • One can't specify a custom error message
  • Running make -t (see Instead of Executing Recipes) will pollute your root directory with lots of check-defined-... files. This is a sad drawback of the fact that pattern rules can't be declared .PHONY.

我相信,可以使用某些 魔术和二次扩展黑客,尽管我不确定是否值得.

I believe, these limitations can be overcome using some eval magic and secondary expansion hacks, although I'm not sure it's worth it.

这篇关于如果未设置变量,则中止makefile的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆