19
votes

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.

4
Works for me - GNU Make 3.82plaes
Works here as well - GNU 3.81Thor
sorry. My example was flawed. I posted an edit with a real examplekalden

4 Answers

44
votes

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

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

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.

1
votes

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