Target-specific make variables

gnu-makemake

How can I force a target-specific variable to be set immediately (line 2)? I want the output of make to be release and make debug to be debug.

X = release
debug: X = debug
debug: all

# the rest is included from an external file; cannot be changed
Y := $(X)
BUILD := $(Y)

all:
    @echo $(BUILD)

Best Answer

Your issue is due to how GNUMake parses a make file.

GNU make does its work in two distinct phases. During the first phase it reads all the makefiles, included makefiles, etc. and internalizes all the variables and their values, implicit and explicit rules, and constructs a dependency graph of all the targets and their prerequisites. During the second phase, make uses these internal structures to determine what targets will need to be rebuilt and to invoke the rules necessary to do so.

Reading Makefiles

It looks as if when you run make debug the dependency is to run all: which prints out the value as if you ran make all. What you need to do is modify your makefile so that all and debug both trigger the same dependency. You'll usually see something like

all: $(executable)
debug: $(executable)
$(executable): $(objs)
    <compile objects to executable>

debug never triggers all but in either case the executable is compiled.

As for your code:

X = release

debug: X = debug

Y = $(X)
BUILD = $(Y)

.PHONY: print
print:
        @echo $(BUILD)

all: print
debug: print

I had to make print be a phony dependency since its not an actual object being created. Otherwise this would be your dependency that both debug and all both require but compile differently depending on the flags you've set.

Related Question