Makefile test if variable is not empty
Solution 1
Note that, due to the time of evaluation, make conditionals (ifeq
, ifneq
...) cannot be used in recipes the way you tried. Use shell conditionals, instead, as shown below.
As your MY_VAR
variable is used only in recipes, is target-dependent and you want it to be computed only when needed, why don't you use shell variables, instead of make variables?
$ cat Makefile
.PHONY: a b
a:
MY_VAR=$$(echo 'whatever') && \
echo '$@: MY_VAR is $$MY_VAR' && \
if [ -n "$$MY_VAR" ]; then \
echo '$@: should be executed'; \
fi && \
echo '$@: done'
b:
MY_VAR=$$(echo '') && \
echo '$@: MY_VAR is $$MY_VAR' && \
if [ -n "$$MY_VAR" ]; then \
echo '$@: should not be executed'; \
fi && \
echo '$@: done'
$ make a
a: MY_VAR is whatever
a: should be executed
a: done
$ make b
b: MY_VAR is
b: done
In case you absolutely need MY_VAR
to be a target-specific make variable, but want to execute only once (per target) the shell command that produces its value, MadScientist has a wonderful trick that you should probably look at. Applied to your case, it should look like:
$ make --version
GNU Make 4.1
...
$ cat Makefile
a: MY_VAR = $(eval a: MY_VAR := $$(shell echo 'whatever'))$(MY_VAR)
b: MY_VAR = $(eval b: MY_VAR := $$(shell echo ''))$(MY_VAR)
a:
@echo '$@: MY_VAR is $(MY_VAR)' && \
if [ -n "$(MY_VAR)" ]; then \
echo '$@: should be executed'; \
fi && \
echo '$@: done'
b:
@echo '$@: MY_VAR is $(MY_VAR)' && \
if [ -n "$(MY_VAR)" ]; then \
echo '$@: should not be executed'; \
fi && \
echo '$@: done'
$ make a
a: MY_VAR is whatever
a: should be executed
a: done
$ make b
b: MY_VAR is
b: done
$ make b a
b: MY_VAR is
b: done
a: MY_VAR is whatever
a: should be executed
a: done
It may look extremely strange but it guarantees that MY_VAR
is computed if and only if targets a
or b
are invoked, and only at most once for each. Have a look at MadScientist's post for detailed explanations. Go, it's brilliant.
Solution 2
If you want to dynamically test the content of MY_VAR
, you may have to :
a:
$(eval MY_VAR = $(shell echo ''))
$(if $(strip $(MY_VAR)),echo ok,echo no)
if
evaluation will become echo ok
if MY_VAR
is not empty, otherwise it will become echo no
Solution 3
The ifeq
and family of conditionals are evaluated when parsing the Makefile. If you want a conditional for a Make variable when expanding a rule, you'll want to use the $(if )
function:
.PHONY: a b
a b:
@$(if $(strip $(MY_VAR)),echo "MY_VAR isn't empty",)
@echo done
a: MY_VAR =
b: MY_VAR = something
cerberos
Updated on June 17, 2022Comments
-
cerberos almost 2 years
In a makefile I'm trying to
- run a shell command and capture the output in a make variable
- do something if the variable is not empty
I've created this simplified makefile to demonstrate my problem. Neither
make a
ormake b
executes the body of the if, I don't understand why not..PHONY: a b a: $(eval MY_VAR = $(shell echo whatever)) @echo MY_VAR is $(MY_VAR) $(info $(MY_VAR)) ifneq ($(strip $(MY_VAR)),) @echo "should be executed" endif @echo done b: $(eval MY_VAR = $(shell echo '')) @echo MY_VAR is $(MY_VAR) $(info $(MY_VAR)) ifneq ($(strip $(MY_VAR)),) @echo "should not be executed" endif @echo done
I'm using
$ make --version GNU Make 3.81
Edit: as pointed out, the vars don't need to be make vars
-
Zelnes almost 6 yearsThere are several problems, and misunderstandings. Your
MY_VAR
is amake
variable, set it without a<tab>
to its value, and no need to$(eval ...)
.MY_VAR:=$(shell echo whatever)
is enough. No<tab>
before$(info ...)
neither, this ismake
-
Zelnes almost 6 yearsIf you want to do something if not empty, you need to use
$(if $(strip $(MY_VAR)),do if,do else)
in the recipe line -
cerberos almost 6 years@Zelnes I only want to set
MY_VAR
when targeta
orb
is run (the real commands are expensive and there are other targets that don't need it), if I remove the tabs I get syntax errors. -
cerberos almost 6 yearsAhh, a different form of if, works! Please make an answer so I can accept.
-
MadScientist almost 6 yearsIf you only want these variables to be set/used within the
a
andb
targets, why make themmake
variables? Why not just use shell variables within the recipe? Trying to usemake
variables here adds a lot of complexity. -
cerberos almost 6 years@MadScientist thanks, it doesn't need to be a make var
-
Toby Speight almost 6 yearsSpecifically, the
ifneq
conditionals happen at a different point to the inline$(if )
conditionals: in parsing the Makefile, not when executing the rule. -
cerberos almost 6 yearswow, such a good answer. Although I specified it should be a make var, it actually doesn't need to be. Thanks