andigor
andigor

Reputation: 732

GNU make strange behavior

I have a simple Makefile:

VAR := aaa
include a.inc
VAR += bbb

and a.inc

some_target: $(VAR)
        @echo "refer to automatic var $^"
        @echo "refer to VAR $(VAR)"

aaa:
bbb:

and when I run make I see a strange print:

refer to automatic var aaa
refer to VAR aaa bbb

Seems that GNU make substitutes $(VAR) in prerequisites at the inclusion moment but $(VAR) in debug print in some later moment. Is this correct behavior ? Why GNU make acts in such non-intuitive way?

Upvotes: 2

Views: 66

Answers (3)

igagis
igagis

Reputation: 2079

GNU make evaluates makefile in 2 passes. Everything is evaluated at first pass, except recipes. Recipes are evaluated at the second pass. So, your reference to $(VAR) in some_target's recipe is evaluated at the second pass, i.e. after the += bbb was appended to VAR, which happened at the end of the first pass.

To achieve the behavior you wanted you can use the following techinique for defining your rule:

define rule
some_target: $(VAR)
    @echo "refer to automatic var $^"
    @echo "refer to VAR $(VAR)"
endef
$(eval $(rule))

Don't forget to use tabs for recipe lines.

Upvotes: 1

Jonathan Wakely
Jonathan Wakely

Reputation: 171461

Make variables set with = (rather than :=) are expanded when they are used.

When you run make first it parses the makefile and determines the targets and prerequisites. At that point VAR gets expanded to its current value.

Then it runs the first target, and executes the recipe for that target, at which point VAR is expanded again, but to its new value.

Upvotes: 2

Etan Reisner
Etan Reisner

Reputation: 81052

It is correct and it isn't unintuitive (though perhaps not immediately obvious).

It works the same way as variables in every other language.

Try this shell example.

$ var=aaa
$ echo "${var}"
aaa
$ ev() { echo "${var}"; }
$ ev
aaa
$ var+=bbb
$ ev
aaabbb

You get the value of a variable as it exists at the time that you use it.

The difference between tgt: prereq and @recipe line in make is when the lines are evaluated.

The GNU Make Manual goes into about this in 3.7 How make Reads a Makefile. Specifically, for this situation, you want the very last sub-section Rule Definition.

Upvotes: 2

Related Questions