191

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

Joseph Quinsey
  • 9,553
  • 10
  • 54
  • 77
prosseek
  • 182,215
  • 215
  • 566
  • 871
  • 10
    possible duplicate of [Makefile variable assignment](http://stackoverflow.com/questions/448910/makefile-variable-assignment) – eldarerathis Feb 02 '11 at 20:40
  • 3
    Possible duplicate of [What is the difference between the GNU Makefile variable assignments =, ?=, := and +=?](https://stackoverflow.com/questions/448910/what-is-the-difference-between-the-gnu-makefile-variable-assignments-a) – Ludovic Kuty Oct 24 '18 at 04:19

7 Answers7

173

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

Czechnology
  • 14,832
  • 10
  • 62
  • 88
Amjad
  • 3,110
  • 2
  • 20
  • 19
  • 8
    "A simple assignment expression is evaluated only once, at the very first occurrence": to be clear, the expansion/evaluation is done when the variable is defined, not the first time it is used. – Michael Burr Apr 22 '20 at 15:32
121

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.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 5
    So would it be correct to say that := is more efficient? Or is efficiency not really a factor with Makefiles? – Ungeheuer Apr 27 '17 at 14:45
  • 5
    @Ungeheuer That's not an issue because process calling (the `make`'s main job) has much larger overhead than such internal variable resolving. – Kirill Bulygin May 15 '17 at 10:51
58

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)
    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)
    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

Edgard Leal
  • 2,592
  • 26
  • 30
  • 1
    `//` isn't a valid comment in Makefiles – Eric May 25 '23 at 07:58
  • 1
    interesting choice of `$(shell sleep 2)` instead of just calling `sleep 2`. The result is really different between the two. Why did you chose `%(shell ...)`? – Eric May 25 '23 at 07:59
  • @Eric, I fixed the usage of the comment. Thanks for the suggestion. About the use of `shell sleep 2`, I think it works well with just `sleep 2`. When I created this answer, I copied this code from a `Makefile` that used the result to assign it to a variable. This is the reason to use `$(shell ...)`, which was something like: `result:=$(find . -type f -name '*js'`. – Edgard Leal May 29 '23 at 13:54
  • 1
    This answer, I like better. – daparic Jun 16 '23 at 13:06
12

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

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

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
6

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.

Andrey Kaipov
  • 635
  • 8
  • 14
1

Recursive assignment = is evaluated everytime it is used, but not in the order of when it is encountered among the recipe commands, but rather before running any recipe command.

Based on the following example:

default: target1 target2

target1 target2:
    @echo "Running at:           `gdate +%s.%N`"
    @echo "Simple assignment:    $(SIMPLE_ASSIGNMENT)"
    @echo "Recursive assignment: $(RECURSIVE_ASSIGNMENT)"
    sleep 1
    @echo "Running at:           `gdate +%s.%N`"
    @echo "Simple assignment:    $(SIMPLE_ASSIGNMENT)"
    @echo "Recursive assignment: $(RECURSIVE_ASSIGNMENT)"
    @echo


SIMPLE_ASSIGNMENT := $(shell gdate +%s.%N)
RECURSIVE_ASSIGNMENT = $(shell gdate +%s.%N)

Outputs:

❯ make
Running at:           1645056840.980488000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056840.958590000
sleep 1
Running at:           1645056842.008998000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056840.969616000

Running at:           1645056842.047367000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056842.027600000
sleep 1
Running at:           1645056843.076696000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056842.035901000
1

= called recursive expanded variable or lazy expanded variable. in below example, when make read this line

VAR1 = $(VAR1) + 100

make just stored value from righthand side VAR1 into lefthand side VAR1 without expanding. When make tried to read $(VAR1) which is defined on left hand side. this is keep repeating and result into infinite loop

VAR1 = 10
VAR2 = 20
VAR3 = 30

# Lazy initialization
VAR1 = $(VAR1) + 100

default:
    echo $(VAR1)

Output:

% make
Makefile:6: *** Recursive variable `VAR1' references itself (eventually).  Stop.

:= called expanded variable or instant

when make read this line, variable on righthand side are expnaded and saved resulting value into left hand side. please see below program output

VAR1 = 10
VAR2 = 20
VAR3 = 30

# instant initialization
VAR1 := $(VAR1) + 100

default:
    echo $(VAR1)

% make
echo 10 + 100
10 + 100

Output:

% make
echo 10 + 100
10 + 100

EDIT: There are already good answer. I came across about this concept on Udemy training course of make with good example.

user8811698
  • 118
  • 1
  • 7