Reputation: 146
I want to detect if "-s" is set in the Makefile command line. Is there a variable that captures make options that I can test?
For example, I want to do something like:
Makefile:
if ($(MAKE_OPTIONS), -s)
#do something
endif
Invocation:
make $(MAKEFILE_OPTIONS) -C some_dir
Upvotes: 0
Views: 2897
Reputation: 11
This is an (updated June 2023) solution that can test for other single-letter flags too and works on GNU Make 3.81 through 4.4.1 (which broke some of the other approaches here). It won't work on anything older than 3.81 though since it uses $(eval …)
.
As described in the comment it defines variables for the flags -s
, -k
, -n
and -q
named $(make-s)
, $(make-k)
, $(make-n)
and $(make-q)
respectively. The flags -i
, -r
and -w
and maybe others too can be detected by extending the list in the $(foreach ...)
function.
makeflags := $(firstword $(filter-out -,$(filter-out --%,$(MAKEFLAGS))))
define checkflags
make-$1 := $(findstring $1,$(makeflags))
endef
# Define $(make-s), $(make-k), $(make-n) and $(make-q)
$(foreach flag,s k n q, $(eval $(call checkflags,$(flag))))
# Answer: Checking for -s:
$(if $(make-s), …silent case…, …noisy case…)
My test Makefile is:
makeflags := $(firstword $(filter-out -,$(filter-out --%,$(MAKEFLAGS))))
define checkflags
make-$1 := $(findstring $1,$(makeflags))
endef
$(foreach flag,i r w s k n q, $(eval $(call checkflags,$(flag))))
$(info MAKEFLAGS = "$(MAKEFLAGS)")
$(foreach flag,i r w s k n q, \
$(info make-$(flag) = "$(make-$(flag))" $(if $(make-$(flag)),YES,NO)))
all:
@+echo 'all: MAKEFLAGS = "$(MAKEFLAGS)"'
@+echo 'all: $(foreach f,i r w s k n q,$(make-$f))'
@+echo ''
Upvotes: 0
Reputation: 546
It turns out there are even more corner cases for MAKEFLAGS
that the below
function doesn't quite cover:
find_s = $(findstring s,$(firstword -$(MAKEFLAGS)))$(filter -s,$(MAKEFLAGS))
Consider the Makefile
below that displays the value of MAKEFLAGS
, both
inside and outside of a recipe, and the result of the find_s
function:
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)'
This correctly detects the absence or presence of the flag -s
, with or
without other single-character switches such as -n
, e.g.:
$ 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'
One corner case is when make
is invoked with "long" switches (starting with
--
) in addition to multiple single-character switches. These single-character
switches will be grouped together in a single word in MAKEFLAGS
in 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'
The grouping of the switches means that the $(filter -s,$(MAKEFLAGS))
expression fails to detect -s
with Make 3.81.
This can be fixed by changing find_s
as follows:
find_s = $(findstring s,$(filter-out --%,$(MAKEFLAGS)))
Switches starting with --
are filtered out, then the remaining content is
scanned for the desired switch (s
), yielding correct detection:
$ 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'
An additional corner case crops up within recipes when variable assignments are
passed on the command-line (e.g., make var=value
); in this case, the variable
MAKEFLAGS
will additionally contain those variable assignments. With
carefully chosen values, both versions of the detection logic find_s
can still
be fooled, e.g.:
$ 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
The simplest cure for this second problem is to save off a copy of MAKEFLAGS
in another variable and use that within recipes, because fortunately outside of
recipes, MAKEFLAGS
won't contain these variable assignments; otherwise, the
more complicated logic below will parse MAKEFLAGS
and stop processing after it
encounters the words =
or --
while filtering out switches starting with
--
:
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)))
This new find_s
correctly detects -s
in all of the below situations:
$ 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'
I'm hopeful that the above techniques work across a broad range of Make versions, but with so many corner cases it's hard to tell; perhaps MadScientist (GNU Make maintainer) can weigh in on this aspect.
Upvotes: 0
Reputation: 100926
Unfortunately it's tricky to find a really portable (across different releases of GNU make) way to do this. Mark's solution gives false positives, if you have set any flag with an "s" in the name (e.g., --warn-undefined-variables
).
In GNU make 4.0 and above, the layout of MAKEFLAGS is well-defined and you can use this:
$(findstring s,$(firstword -$(MAKEFLAGS))
to robustly and reliably tell if -s
was given. However this won't work reliably in versions of GNU make prior to 4.0. You can use this:
$(findstring s,$(firstword -$(MAKEFLAGS)))$(filter -s,$(MAKEFLAGS))
This expands to the empty string if -s
was not given, or a non-empty string if it was. I believe that will work in all versions of GNU make.
Upvotes: 2
Reputation: 6395
No, filter
is not the one. Use findstring
:
ifneq ($(findstring s, $(MAKEFLAGS)),)
...
endif
or
$(if $(findstring s, $(MAKEFLAGS)),...)
Upvotes: 0
Reputation: 99144
The variable you're looking for is MAKEFLAGS
.
ifeq ($(filter s, $(MAKEFLAGS)),s)
# do something
endif
Upvotes: 0