131
votes

For variable assignment in Make, I see := and = operator. What's the difference between them?

5

5 Answers

102
votes

This is described in the GNU Make documentation, in the section titled 6.2 The Two Flavors of Variables .

In short, variables defined with := are expanded once, but variables defined with = are expanded whenever they are used.

99
votes

Simple assignment :=

A simple assignment expression is evaluated only once, at the very first occurrence. For example, if CC :=${GCC} ${FLAGS} during the first encounter is evaluated to gcc -W then each time ${CC} occurs it will be replaced with gcc -W.

Recursive assignment =

A Recursive assignment expression is evaluated everytime the variable is encountered in the code. For example, a statement like CC = ${GCC} {FLAGS} will be evaluated only when an action like ${CC} file.c is executed. However, if the variable GCC is reassigned i.e GCC=c++ then the ${CC} will be converted to c++ -W after the reassignment.

Conditional assignment ?=

Conditional assignment assigns a value to a variable only if it does not have a value

Appending +=

Assume that CC = gcc then the appending operator is used like CC += -w
then CC now has the value gcc -W

For more check out these tutorials

12
votes

From http://www.gnu.org/software/make/manual/make.html#Flavors:

= defines a recursively-expanded variable. := defines a simply-expanded variable.

12
votes

For me, the best way to see it in practice is during this Makefile snippet:

Simple assignment

XX := $(shell date) // date will be executed once
tt:
    @echo $(XX)
    $(shell sleep 2)
    @echo $(XX)

Running

make tt

Will produce:

sex 22 jan 2021 14:56:08 -03
sex 22 jan 2021 14:56:08 -03

( Same value )

Expanded assignment

XX = $(shell date) // date will be executed every time you use XX
tt:
    @echo $(XX)
    $(shell sleep 2)
    @echo $(XX)

Running

make tt

Will produce:

sex 22 jan 2021 14:56:08 -03
sex 22 jan 2021 14:56:10 -03

Different values

1
votes

This is an old question but this example helps me understand the difference whenever I forget.

Running make with the following Makefile will instantly exit:

a = $(shell sleep 3)

Running make with the following Makefile will sleep for 3 seconds, and then exit:

a := $(shell sleep 3)

In the former Makefile, a is not evaluated until it's used elsewhere in the Makefile, while in the latter a is evaluated immediately even though it's not used.