Skip to content

Pattern Rules

Scope: one rule that builds every .o from its .c — how % works and when patterns don't apply.

The repetition problem

The C build has two nearly identical compile rules:

main.o: main.c greet.h
    $(CC) $(CFLAGS) -c $< -o $@

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

Add ten more source files and you have ten more copies. A pattern rule replaces them all:

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

% matches any stem — the part that's the same on both sides. Asking for main.o matches with stem main, so the prerequisite becomes main.c (plus greet.h). One rule, any number of source files.

This is the rule the real build in A Real C Build uses, and the output is identical:

$ make
gcc -Wall -Wextra -g -c main.c -o main.o
gcc -Wall -Wextra -g -c greet.c -o greet.o
gcc -Wall -Wextra -g -o hello main.o greet.o

Built-in patterns

Make ships with pattern rules for the common cases — compiling C, C++, Fortran, assembling, even TeX. Watch what happens with a Makefile that has only the dependency line:

hello: main.o greet.o
$ make
cc    -c -o main.o main.c
cc    -c -o greet.o greet.c

The compiles happened with no recipe at all — Make's built-in %.o: %.c rule handled them (the odd spacing is Make echoing the exact command). But notice what didn't happen: no linked hello binary. The built-in link rule only covers the single-object case (hello from hello.o), so multi-object programs still need their own link recipe:

hello: main.o greet.o
    $(CC) -o $@ $^

Built-ins are why tiny Makefiles work at all — and why defining your own CC and CFLAGS customizes every built-in rule at once.

Check: make -p | grep -A1 '^%.o:' lists the built-in pattern rules. There are more than you'd guess.

Limits

Patterns match file names, not arbitrary text — %.o: %.c can't express "object files in build/ from sources in src/" without help (that's what $(patsubst ...) and vpath are for; look them up when you need them). And a pattern rule only fires if Make can't find an explicit rule first — explicit always beats pattern.