Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Make as a Dependency Graph

โญโญโญ advancedโณ 16 min read๐Ÿ“ Lesson 193 of 225

Targets, prerequisites, recipes, automatic variables, and why incremental builds are correct only when dependencies are complete.

The whole model in three sentences

A Makefile states: a target depends on prerequisites, and a recipe rebuilds it when any prerequisite is newer. Make walks this graph bottom-up, skipping everything already up to date. That is the entire theory.

CC = gcc
CFLAGS = -std=c23 -Wall -Wextra -O2

app: main.o util.o
	$(CC) main.o util.o -o app

%.o: %.c util.h
	$(CC) $(CFLAGS) -c $< -o $@

$< is the first prerequisite, $@ the target, %.o: %.c a pattern rule โ€” three pieces of syntax covering most real builds.

Incompleteness is the classic failure

If util.o's rule forgets its dependency on util.h, editing util.h rebuilds nothing โ€” the build succeeds while shipping stale objects. Missing dependencies do not fail loudly; they lie quietly. Header dependency generators (-MMD -MP) exist precisely because humans forget.

Order-only and phony targets

Directories as prerequisites should be order-only (| bin), and non-file targets like clean must be declared .PHONY โ€” or a stray file named clean silently disables it.

โšก Now practice

Ready to Code
Build Model DrillsMake's graph semantics and warning-class knowledge, as executable functions โ€” the build system as testable design.
3 challenges ยท ยท ~20 min