MAKEFLAGS
事实证明,下面的函数还没有完全涵盖更多的极端情况:
find_s = $(findstring s,$(firstword -$(MAKEFLAGS)))$(filter -s,$(MAKEFLAGS))
考虑Makefile
下面显示MAKEFLAGS
配方内部和外部的值,以及find_s
函数的结果:
find_s = $(findstring s,$(firstword -$(MAKEFLAGS)))$(filter -s,$(MAKEFLAGS))
$(info Outside a recipe, MAKEFLAGS="$(MAKEFLAGS)")
$(info $(if $(find_s),-s was detected,-s not found))
all:
@echo 'Inside a recipe, MAKEFLAGS="$(MAKEFLAGS)"'
@echo '$(if $(find_s),-s was detected,-s not found)'
这可以正确检测 flag 的缺失或存在,无论是否有-s
其他单字符开关,例如-n
,例如:
$ make-3.81
Outside a recipe, MAKEFLAGS=""
-s not found
Inside a recipe, MAKEFLAGS=""
-s not found
$ make-4.1
Outside a recipe, MAKEFLAGS=""
-s not found
Inside a recipe, MAKEFLAGS=""
-s not found
$ make-3.81 -s
Outside a recipe, MAKEFLAGS="s"
-s was detected
Inside a recipe, MAKEFLAGS="s"
-s was detected
$ make-4.1 -s
Outside a recipe, MAKEFLAGS="s"
-s was detected
Inside a recipe, MAKEFLAGS="s"
-s was detected
$ make-3.81 -s -n
Outside a recipe, MAKEFLAGS="sn"
-s was detected
echo 'Inside a recipe, MAKEFLAGS="sn"'
echo '-s was detected'
$ make-4.1 -s -n
Outside a recipe, MAKEFLAGS="ns"
-s was detected
echo 'Inside a recipe, MAKEFLAGS="ns"'
echo '-s was detected'
除了多个单字符开关之外,一个极端情况是make
使用“长”开关(以 开头)调用
when 。--
这些单字符开关将MAKEFLAGS
在 Make 3.81 中组合成一个单词:
$ make-3.81 -n -s --warn-undefined-variables
Outside a recipe, MAKEFLAGS=" --warn-undefined-variables -sn"
-s not found
echo 'Inside a recipe, MAKEFLAGS=" --warn-undefined-variables -sn"'
echo '-s not found'
$ make-4.1 -n -s --warn-undefined-variables
Outside a recipe, MAKEFLAGS="ns --warn-undefined-variables"
-s was detected
echo 'Inside a recipe, MAKEFLAGS="ns --warn-undefined-variables"'
echo '-s was detected'
开关的分组意味着$(filter -s,$(MAKEFLAGS))
表达式无法-s
使用 Make 3.81 进行检测。
这可以通过find_s
如下更改来解决:
find_s = $(findstring s,$(filter-out --%,$(MAKEFLAGS)))
过滤掉以 开头的开关--
,然后扫描剩余内容以查找所需开关 ( s
),从而产生正确的检测:
$ make-3.81 -n -s --warn-undefined-variables
Outside a recipe, MAKEFLAGS=" --warn-undefined-variables -sn"
-s was detected
echo 'Inside a recipe, MAKEFLAGS=" --warn-undefined-variables -sn"'
echo '-s was detected'
当在命令行上传递变量赋值时,配方中会出现一个额外的极端情况(例如,make var=value
);在这种情况下,变量
MAKEFLAGS
将另外包含这些变量分配。通过仔细选择的值,两个版本的检测逻辑find_s
仍然可以被愚弄,例如:
$ make-3.81 var='fake -s'
Outside a recipe, MAKEFLAGS=""
-s not found
Inside a recipe, MAKEFLAGS="var=fake\ -s"
-s was detected
$ make-4.1 var='fake -s'
Outside a recipe, MAKEFLAGS=""
-s not found
Inside a recipe, MAKEFLAGS=" -- var=fake\ -s"
-s was detected
解决第二个问题的最简单方法是MAKEFLAGS
在另一个变量中保存副本并在配方中使用它,因为幸运的是在配方之外,MAKEFLAGS
不会包含这些变量分配;否则,下面更复杂的逻辑将在遇到单词或过滤掉以 开头的开关
MAKEFLAGS
后解析并停止处理:=
--
--
empty :=
space := $(empty) $(empty)
# Define variable " " to avoid warnings with --warn-undefined-variables.
$(space) :=
parseFlags = $\
$(if $(findstring =,$(firstword $1)),$\
$(empty),$\
$(if $(firstword $1),$\
$(if $(filter-out --%,$(firstword $1)),$\
$(subst -,$(empty),$(firstword $1)))$\
$(if $(filter-out --,$(firstword $1)),$\
$(call $0,$(wordlist 2,$(words $1),$1)))))
find_s = $(findstring s,$(call parseFlags,$(MAKEFLAGS)))
此新功能可在以下所有情况下find_s
正确检测:-s
$ make-3.81 var='fake -s'
Outside a recipe, MAKEFLAGS=""
-s not found
Inside a recipe, MAKEFLAGS="var=fake\ -s"
-s not found
$ make-4.1 var='fake -s'
Outside a recipe, MAKEFLAGS=""
-s not found
Inside a recipe, MAKEFLAGS=" -- var=fake\ -s"
-s not found
$ make-3.81 var='fake -s' -ns --warn-undefined-variables
Outside a recipe, MAKEFLAGS=" --warn-undefined-variables -sn"
-s was detected
echo 'Inside a recipe, MAKEFLAGS=" --warn-undefined-variables -sn -- var=fake\ -s"'
echo '-s was detected'
$ make-4.1 var='fake -s' -ns --warn-undefined-variables
Outside a recipe, MAKEFLAGS="ns --warn-undefined-variables"
-s was detected
echo 'Inside a recipe, MAKEFLAGS="ns --warn-undefined-variables -- var=fake\ -s"'
echo '-s was detected'
我希望上述技术适用于广泛的 Make 版本,但有如此多的极端情况很难说;也许 MadScientist(GNU Make 维护者)可以在这方面进行权衡。