What is the difference between the GNU Makefile variable assignments =, ?=, := and +=?

Can anybody give a clear explanation of how variable assignment really works in Makefiles.

What is the difference between :

 VARIABLE = value
 VARIABLE ?= value
 VARIABLE := value
 VARIABLE += value

I have read the section in GNU Make's manual, but it still doesn't make sense to me.


Solution 1:

Lazy Set

VARIABLE = value

Normal setting of a variable, but any other variables mentioned with the value field are recursively expanded with their value at the point at which the variable is used, not the one it had when it was declared

Immediate Set

VARIABLE := value

Setting of a variable with simple expansion of the values inside - values within it are expanded at declaration time.

Lazy Set If Absent

VARIABLE ?= value

Setting of a variable only if it doesn't have a value. value is always evaluated when VARIABLE is accessed. It is equivalent to

ifeq ($(origin VARIABLE), undefined)
  VARIABLE = value
endif

See the documentation for more details.

Append

VARIABLE += value

Appending the supplied value to the existing value (or setting to that value if the variable didn't exist)

Solution 2:

Using = causes the variable to be assigned a value. If the variable already had a value, it is replaced. This value will be expanded when it is used. For example:

HELLO = world
HELLO_WORLD = $(HELLO) world!

# This echoes "world world!"
echo $(HELLO_WORLD)

HELLO = hello

# This echoes "hello world!"
echo $(HELLO_WORLD)

Using := is similar to using =. However, instead of the value being expanded when it is used, it is expanded during the assignment. For example:

HELLO = world
HELLO_WORLD := $(HELLO) world!

# This echoes "world world!"
echo $(HELLO_WORLD)

HELLO = hello

# Still echoes "world world!"
echo $(HELLO_WORLD)

HELLO_WORLD := $(HELLO) world!

# This echoes "hello world!"
echo $(HELLO_WORLD)

Using ?= assigns the variable a value iff the variable was not previously assigned. If the variable was previously assigned a blank value (VAR=), it is still considered set I think. Otherwise, functions exactly like =.

Using += is like using =, but instead of replacing the value, the value is appended to the current one, with a space in between. If the variable was previously set with :=, it is expanded I think. The resulting value is expanded when it is used I think. For example:

HELLO_WORLD = hello
HELLO_WORLD += world!

# This echoes "hello world!"
echo $(HELLO_WORLD)

If something like HELLO_WORLD = $(HELLO_WORLD) world! were used, recursion would result, which would most likely end the execution of your Makefile. If A := $(A) $(B) were used, the result would not be the exact same as using += because B is expanded with := whereas += would not cause B to be expanded.

Solution 3:

I suggest you do some experiments using "make". Here is a simple demo, showing the difference between = and :=.

/* Filename: Makefile*/
x := foo
y := $(x) bar
x := later

a = foo
b = $(a) bar
a = later

test:
    @echo x - $(x)
    @echo y - $(y)
    @echo a - $(a)
    @echo b - $(b)

make test prints:

x - later
y - foo bar
a - later
b - later bar

Check more elaborate explanation here

Solution 4:

When you use VARIABLE = value, if value is actually a reference to another variable, then the value is only determined when VARIABLE is used. This is best illustrated with an example:

VAL = foo
VARIABLE = $(VAL)
VAL = bar

# VARIABLE and VAL will both evaluate to "bar"

When you use VARIABLE := value, you get the value of value as it is now. For example:

VAL = foo
VARIABLE := $(VAL)
VAL = bar

# VAL will evaluate to "bar", but VARIABLE will evaluate to "foo"

Using VARIABLE ?= val means that you only set the value of VARIABLE if VARIABLE is not set already. If it's not set already, the setting of the value is deferred until VARIABLE is used (as in example 1).

VARIABLE += value just appends value to VARIABLE. The actual value of value is determined as it was when it was initially set, using either = or :=.