Programming Utilities Guide

Processing Dependencies

After make begins, it processes targets as it encounters them in its depth-first dependency scan. For example, with the following makefile:

batch: a b 
     touch batch 
b: 
     touch b 
a: 
     touch a 
c: 
     echo "you won't see me"

make starts with the target batch. Since batch has some dependencies that have not been checked, namely a and b, make defers batch until after it has checked a and b against any dependencies they might have.

Graphic

Since a has no dependencies, make processes it; if the file is not present, make performs the rule in its target entry.

$ make 
touch a 
...

Next, make works its way back up to the parent target batch. Since there is still an unchecked dependency b, make descends to b and checks it.

Graphic

b also has no dependencies, so make performs its rule:

...
touch b 
...

Finally, now that all of the dependencies for batch have been checked and built (if needed), make checks batch.

Graphic

Since it rebuilt at least one of the dependencies for batch, make assumes that batch is out of date and rebuilds it; if a or b had not been built in the current make run, but were present in the directory and newer than batch, make's time stamp comparison would also result in batch being rebuilt:

...
touch batch

Target entries that are not encountered in a dependency scan are not processed. Although there is a target entry for c in the makefile, make does not encounter it while performing the dependency scan for batch, so its rule is not performed. You can select an alternate starting target like c by entering it as an argument to the make command.

In the next example, the batch target produces no file. Instead, it is used as a label to group a set of targets.

batch: a b c 
a: a1 a2 
      touch a
b: 
      touch b 
c: 
      touch c
a1: 
      touch a1
a2: 
      touch a2

In this case, the targets are checked and processed, as shown in the following diagram:

Graphic

Essentially, make then:

  1. Checks batch for dependencies, notices that there are three, and so defers it.

  2. Checks a, the first dependency, and notices that it has two dependencies of its own. Continuing in like fashion, make:

    1. Checks a1, and if necessary, rebuilds it.

    2. Checks a2, and if necessary, rebuilds it.

  3. Determines whether to build a.

  4. Checks b and rebuilds it if necessary.

  5. Checks and rebuilds c if necessary.

  6. After traversing its dependency tree, make checks and processes the topmost target, batch. If batch contains a rule, make performs that rule. Here batch has no rule, therefore make performs no action, but notes that batch has been rebuilt; any targets depending on batch would also be rebuilt.