我想检测是否在Makefile命令行中设置了“-s”。是否有一个变量可以捕获我可以测试的make选项?
例如,我想做类似的事情:
Makefile文件:
if ($(MAKE_OPTIONS), -s)
#do something
endif
调用:
make $(MAKEFILE_OPTIONS) -C some_dir
不幸的是,找到一个真正可移植的(跨GNU make的不同版本)方法是很棘手的。如果您在名称中设置了带有“s”的标志(例如,--warn-undefined-variables
),Mark的解决方案会给出误报。
在GNU make 4.0及以上版本中,MAKEFLAGS的布局是明确定义的,您可以使用:
$(findstring s,$(firstword -$(MAKEFLAGS))
能够有力而可靠地判断是否给出了-s
。但是,这在4.0之前的GNU make版本中无法可靠地工作。你可以用这个:
$(findstring s,$(firstword -$(MAKEFLAGS)))$(filter -s,$(MAKEFLAGS))
如果没有给出-s
,则扩展为空字符串,如果是,则扩展为非空字符串。我相信这将适用于所有版本的GNU make。
你要找的变量是MAKEFLAGS
。
ifeq ($(filter s, $(MAKEFLAGS)),s)
# do something
endif
不,filter
不是那个。使用findstring
:
ifneq ($(findstring s, $(MAKEFLAGS)),)
...
endif
要么
$(if $(findstring s, $(MAKEFLAGS)),...)
事实证明,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)'
这正确地检测到标志-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
开始)调用--
。这些单字符开关将在Make 3.81中的MAKEFLAGS
中的单个单词中组合在一起:
$ 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))
表达式无法用Make 3.81检测-s
。
这可以通过更改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 maintainer)可以在这方面权衡。