In a makefile I'm trying to
I've created this simplified makefile to demonstrate my problem. Neither make a or make 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
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With