5
votes

In the GNU-Make manual the How make Reads a Makefile https://www.gnu.org/software/make/manual/make.html#Reading-Makefiles sections says

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.

I am not able to understand the difference b/w the two phases clearly. May be looking at an example will help understand. Are there any links or tutorials which clarifies what exactly happens in the first phase and second phase.

1

1 Answers

9
votes

Take this trivial makefile:

var := some_other_file

some_file: $(var)
  some_command $^ $@

After phase one the file will look like the following

var := some_other_file

some_file: some_other_file
  some_command $^ $@

Notice how $^ and $@ haven't been expanded yet, recipes are only expanded and invoked as part of phase 2.

In phase 2, make will use the rules resulting from phase 1 and determine which targets need to be remade, you can see how make "thinks" by running make with the -d flag (warning: lots of output).

During phase 2 of the above case, after having checked all of some_other_file's dependencies and remade it if necessary, it then considers whether some_other_file is newer then some_file.

If this is the case then (and only then) are the recipes' variables expanded, and the contents of each line is passed to the shell, which here would be some_command some_other_file some_file.

It follows that you can't use $@ etc. anywhere except as part of a recipe because automatic variables are only set during phase 2.

foo: $@bar
  some_command $^

This will be expanded in phase 1 to:

foo: bar
  some_command $^

Which during phase 2 will result in:

foo: bar
  some_command bar

Probably not what you wanted.

Some makes have ways of working around this limitation. GNU make for instance has .SECONDEXPANSION, and the following will work as expected:

.SECONDEXPANSION:
foo: $$@bar
  some_command $^

Anything after .SECONDEXPANSION will be expanded both during phase 1:

.SECONDEXPANSION:
foo: $@bar
  some_command $^

and phase 2:

.SECONDEXPANSION:
foo: foobar
  some_command foobar