Search code examples
makefile

Makefile test if variable is not empty


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 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


Solution

  • 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.