← All 71 books GNU make starters, one move per page Get the full edition · £10
One move per page

GNU make starters, one move per page

Twenty-seven steps for people who type make daily and trust it blindly: the rule shape with its famous tab, the timestamps that decide what rebuilds, the first target as the front door, phony names like clean and all that aren't files, $@ and $< and friends that let a rule name itself, one % pattern rule doing the work of twenty, static patterns, variables defined once, wildcards under two masters, the @ and - per-line signs, -n the rehearsal, -k the survey, -j the job slots, recursive $(MAKE) -C, and the whole tool on one page, one move per page.


Steve Hodgkiss 5 steps

A diagram, the classic trap, and one thing to go try this week. That's a page.

GNU make starters, one move per page

Twenty-seven steps for people who type make daily and trust it blindly: the rule shape with its famous tab, the timestamps that decide what rebuilds, the first target as the front door, phony names like clean and all that aren't files, $@ and $< and friends that let a rule name itself, one % pattern rule doing the work of twenty, static patterns, variables defined once, wildcards under two masters, the @ and - per-line signs, -n the rehearsal, -k the survey, -j the job slots, recursive $(MAKE) -C, and the whole tool on one page, one move per page.


Set in Space Grotesk, Inter and JetBrains Mono (SIL Open Font License).

GNU make behaviour checked against the GNU Make Manual (gnu.org/software/make/manual, make.info from the GNU make 4.4.1 release), fetched and read during this build, with behaviours spot-checked live against GNU Make 4.3. Flags, defaults, limits and edge cases are named as the manual names them. Teaching conventions (one move a page) are named as conventions. This book quotes no verbatim passages and is an independent guide not affiliated with or endorsed by the GNU Project or the Free Software Foundation.

General information only. Not professional advice; verify against your own make and the current documentation.

Your purchase is for personal use only. You do not have redistribution rights: please do not share, resell, or republish this book or its pages.

© 2026 Steve Hodgkiss. All rights reserved. Personal use only; no redistribution rights.

Edition 1.0 · stevehodgkiss.net

Contents

Contents


Part 1 · The model4
The rule, whole5
Timestamps decide6
Part 2 · First moves
The tab7
Part 3 · Names for actions
.PHONY8
Part 4 · Steering
-n, the rehearsal9
Part 1 of 4
rule, times, graph
1

The model

What make is underneath: the one rule shape with its famous tab, the modification times that decide what rebuilds, the first target as the front door, and the graph that orders it all.


In this part
  1. 01The rule, whole
  2. 02Timestamps decide

Per the GNU Make Manual 2.1 What a Rule Looks Like: a simple makefile consists of rules with the shape target: prerequisites, then a recipe, and you need to put a tab character at the beginning of every recipe line. A target is usually the name of a file that is generated by a program; a prerequisite is a file that is used as input to create the target.

make starters · No. 01
The model

The rule, whole

Target, prerequisites, tab, recipe

one shape, three named parts, one tabTARGETedit:PREREQUISITESmain.o util.oTABmust begin every recipe linecc -o edit main.o util.oa file the recipebuildsfiles it isbuilt fromshell linesevery Makefile is made of these

Let's say every Makefile you've read looked like noise. There's one shape underneath: target, colon, prerequisites, recipe.

The target is usually a file the recipe builds. The prerequisites are the files it's built from. The recipe is shell commands, and the manual is blunt about the catch: you need a tab at the beginning of every recipe line. That one obscurity, the manual's own word, catches the unwary.

Three lines and a tab. Every Makefile you'll ever read is made of these.

TRY THIS WEEK

Write a three line rule for a file you actually build this week, and run make on it.

Per the GNU Make Manual 4.2 Rule Syntax: a target is out of date if it does not exist or if it is older than any of the prerequisites, by comparison of last-modification times. The idea is that the contents of the target file are computed based on information in the prerequisites.

make starters · No. 02
The model

Timestamps decide

Newer in, rebuild out

newer prerequisite in, rebuild outmain.c10:04util.c09:30main.o10:01older thanmain.cutil.o09:31newer thanutil.crebuildmain.oskiputil.oit never reads contents, only modification times

Let's say you run make twice and the second time says 'up to date'. What was checked?

Times, nothing else. A target is out of date when it doesn't exist, or when any prerequisite is newer, compared by last-modified time. make never reads the contents to decide. The reasoning in the manual: the target is computed from the prerequisites, so a changed prerequisite makes the existing target's contents no longer necessarily valid.

It compares labels on the boxes, not what's inside them.

TRY THIS WEEK

Build something with make, touch one source file, and rerun. Watch only that branch rebuild.

Per the GNU Make Manual 2.1: you need a put a tab character at the beginning of every recipe line; this is an obscurity that catches the unwary. If you prefer another prefix you can set the .RECIPEPREFIX variable. Live GNU Make 4.3 prints: missing separator (did you mean TAB instead of 8 spaces?).

make starters · No. 03
First moves

The tab

Spaces fail the parse

same look, different bytes, different outcomeTABcc -c main.ca real tab: parsescc -c main.ceight spaces: parse failsmakeMakefile:2: *** missing separator(did you mean TAB instead of 8 spaces?). Stop.fix the editor once: emit tabs for Makefiles

Let's say make refuses with 'missing separator'. Count your editor's indent characters.

Every recipe line must begin with a real tab. Eight spaces look identical to you and are a different byte to make, and modern versions even guess at your mistake in the error. The one escape is setting .RECIPEPREFIX to another character, for the editors and the stubborn. Fix the editor to emit tabs, once, and this error never comes back.

The most famous wart in the tool, and it's one settings screen.

TRY THIS WEEK

Set your editor to show whitespace this week and convert any Makefile you own to tabs.

Per the GNU Make Manual 4.6 Phony Targets: a phony target is one that is not really the name of a file, just a name for a recipe. If a file named clean is ever created, clean would always be considered up to date and its recipe would not be executed. Declare it phony by making it a prerequisite of .PHONY, then make clean runs the recipe regardless.

make starters · No. 04
Names for actions

.PHONY

A name, not a file

a file with the wrong name silences the actionclean (a file!)make clean'clean' is up to date. refused..PHONY: cleanmake cleanruns the recipe regardless of any file.PHONY: cleanclean:rm *.o tempthe name is a recipe,not a promise of a fileimplicit rule searchskipped for phony targets

Let's say a file named clean ever lands in the directory. make clean now refuses: it sees the file, no prerequisites, up to date.

The fix is declaring the name: .PHONY: clean makes it a prerequisite of a special target, and the recipe runs regardless of any file. Phony means not-a-file, an action wearing a target's clothes. It's also a small speedup, the manual notes: implicit rule search is skipped for phony targets.

If the recipe doesn't build a file with the target's name, that target is phony. Say so.

TRY THIS WEEK

List every action target in a Makefile you own and add one .PHONY line for all of them.

Per the GNU Make Manual 9.3 Instead of Executing Recipes: -n, --just-print, --dry-run causes make to print the recipes needed to make the targets up to date but not actually execute them; some recipes are still executed even with this flag, such as recipes using $(MAKE). -t marks targets as up to date by updating modified times. -q silently checks, with exit status zero if up to date, one if updates are needed, two on error.

make starters · No. 05
Steering

-n, the rehearsal

Print, don't run

read the plan before it runsmake -n appcc -c main.ccc -o app main.oprinted, not runmake appcc -c main.ccc -o app main.oexecuted-ttouch: mark fresh-q0 fresh, 1 needs work, 2 error$(MAKE) lines still run under -n

Let's say the build might delete or overwrite something you care about. Read the plan first.

-n prints every recipe it would run, executing nothing, the same rehearsal habit as rsync's dry run. Its siblings: -t marks targets fresh by touching times, and -q says nothing and answers by exit code, 0 up to date, 1 needs work, 2 error, made for scripts. One caveat the manual flags: lines involving $(MAKE) still run under -n, recursion must recurse.

Destructive target, or borrowed Makefile? -n before enter.

TRY THIS WEEK

Run make -n against an unfamiliar Makefile this week and read the whole plan before trusting it.

Index

Index


-n, the rehearsal9
.PHONY8
The rule, whole5
The tab7
Timestamps decide6