25

The following is a very simple makefile that does not seem to work properly.

TEST=ON

buildbegin:
ifeq ($(TEST),ON)        
    @echo TEST PASSED
else
    @echo TEST FAILED
endif

No matter what I set the TEST variable to, my ifeq statement passes. I always see TEST PASSED. Anyone see what I am doing wrong here?

EDIT:

ok. my example was not exactly accurate. What I actually have is this:

SHELL = /bin/sh

DEFAULT_TARGS:= all  all_debug  
DEBUG_TARGS:= all_debug
ALL_TARGS:= $(DEFAULT_TARGS) $(DEBUG_TARGS)

.PHONY: $(ALL_TARGS)
.PHONY: buildbegin

$(ALL_TARGS): buildbegin

TEST=ON

$(DEBUG_TARGS): TEST=OFF

buildbegin:
    @echo $(TEST)
ifeq ($(TEST),ON)
    @echo PASSED
else
    @echo FAILED
endif

Running either make all or make all_debug will result in "PASSED" being printed. If I echo $(TEST) before the condition, it looks as if my rules are changing the variable, but the ifeq only ever sees whatever the default value is.

Jack Kelly
  • 18,264
  • 2
  • 56
  • 81
kalden
  • 273
  • 1
  • 3
  • 5

4 Answers4

51

make evaluates conditionals when it reads a makefile (as you know it uses 2 passes), see: Conditional Parts of Makefiles. You can simply check this by using warning (which is good thing to debug makefiles):

buildbegin:
    @echo $(TEST)
$(warning now we reached ifeq TEST=$(TEST))
ifeq ($(TEST),ON)
    @echo PASSED
else
    @echo FAILED
endif

You should use shell commands instead and include them in rule:

buildbegin:
      @if [ "$(TEST)" = "ON" ]; then echo "PASSED"; else echo "FAILED"; fi
Sam
  • 334
  • 3
  • 7
pmod
  • 10,450
  • 1
  • 37
  • 50
  • 1
    @user1604180 Welcome to SO! If this answer is the right one (and definitely, it is), you should [accept](http://stackoverflow.com/faq#howtoask) it. – Eldar Abusalimov Aug 16 '12 at 23:28
  • 1
    @kralyk thanks for pointing at this, it should be $(TEST) actually in this case, because we want this to be evaluated by make. But if you need evaluation within shell (not in this example), then yes - you should use $$TEST. But note that every line is executed in own shell process, so in this case you need to evaluate "within one make line before testing" – pmod Dec 02 '16 at 10:10
4

Here's a cleaner (I think, anyway) way to do what you want:

all:
    $(MAKE) TEST=ON buildbegin

all_debug:
    $(MAKE) TEST=OFF buildbegin

buildbegin:
    @echo $(TEST)
ifeq ($(TEST),ON)
    @echo PASSED
else
    @echo FAILED
endif
twalberg
  • 59,951
  • 11
  • 89
  • 84
2

Parameterise the shell command using make variables. This avoids recursive make and even the shell (make will fork the command directly and not go via a shell if the command contains no shell metacharacters (<>"&; and the like)).

Something like:

result<ON> := PASSED
result<OFF> := FAILED

buildbegin:
    @echo ${result-<${TEST}>}

The <...> is simply a convention to indicate some sort of indirection.

bobbogo
  • 14,989
  • 3
  • 48
  • 57
1

Although the question is old, I want to share a simpler way.

It is to use MAKECMDGOALSvariable that represents the list of targets.

In your case, a solution maybe:

buildbegin:
    @echo $(MAKECMDGOALS)
ifeq ($(MAKECMDGOALS),all)
    @echo PASSED
else ifeq ($(MAKECMDGOALS),debug_all)
    @echo FAILED
endif


debug_all: buildbegin

all: buildbegin

Usage: make debug_all or make all

nhnghia
  • 725
  • 9
  • 8