make program attempts to bring a target up to date by bring all of the target's dependencies up to date. These dependencies may have further dependencies. Thus, a potentially complex dependency graph forms when processing a typical `Makefile' . From a simple `Makefile' that looks like this:
| || |
all: foo foo: foo.o bar.o baz.o .c.o: $(CC) $(CFLAGS) -c $< -o $@ .l.c: $(LEX) $< && mv lex.yy.c $@
We can draw a dependency graph that looks like this:
| || |
all foo .-------+-------. / \ foo.o bar.o baz.o foo.c bar.c baz.c baz.l
Unless the `Makefile' contains a directive to
make , all targets are assumed to be filename and rules must be written to create these files or somehow bring them up to date.
When leaf nodes are found in the dependency graph, the `Makefile' must include a set of shell commands to bring the dependent up to date with the dependency. Much to the chagrin of many
make users, up to date means the dependent has a more recent timestamp than the target. Moreover, each of these shell commands are run in their own sub-shell and, unless the `Makefile' instructs
make otherwise , each command must exit with an exit code of 0 to indicate success.
Target rules can be written which are executed unconditionally. This is achieved by specifying that the target has no dependents. A simple rule which should be familiar to most users is: