如果未设置变量,则中止makefile [英] Abort makefile if variable not set
问题描述
如何基于未设置/赋值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 ofcheck-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屋!