glunty

Makefile Cheat Sheet

A searchable reference of GNU make syntax with a plain-English note on what each part does.

GNU make syntax with a plain-English description of what each part does
Syntax What it does
target: prerequisites Basic rule header; make updates each prerequisite first, then runs the recipe if the target is missing or older than a prerequisite.
<tab>recipe command A recipe line must start with a real TAB, not spaces; each line runs in its own shell to build the target.
foo.o: foo.c foo.h A concrete rule: rebuild foo.o whenever foo.c or foo.h is newer than it.
a.o b.o: common.h Give several targets the same prerequisite and recipe; make applies the rule once for each target.
%.o: %.c Pattern rule: build any .o file from the matching .c file, where % is the shared stem.
$(OBJS): %.o: %.c Static pattern rule: apply a pattern rule only to the listed targets, not to every possible match.
target: normal | order-only Prerequisites after the pipe must exist but do not force a rebuild when they change, handy for output directories.
clean: A target that is not a real file (like clean or all); list it under .PHONY so its recipe always runs.
# first target is the default goal With no argument make builds the default goal, which is the first normal target defined in the file.
# rule order does not set build order make builds prerequisites in dependency order rather than top to bottom, so rules can appear in any order.
VAR = value Recursively expanded variable: references inside value are expanded each time VAR is used, so it can point at things defined later.
VAR := value Simply expanded variable: the right side is expanded once, immediately, using only what is defined so far.
VAR ?= value Conditional set: assign value only if VAR has no value yet, leaving any existing definition alone.
VAR += more Append a space and more to VAR, keeping whichever flavor (recursive or simple) it already had.
VAR != command Shell assignment: run command once and store its output in VAR, similar to := combined with the shell function.
$(VAR) Read a variable value; the brace form works too. Use $$ when a recipe needs a literal dollar sign.
override VAR = value Keep this value even when the same variable is passed on the command line, which normally overrides the file.
export VAR Put VAR into the environment of every recipe subshell that make starts.
target: VAR = value Target-specific variable: VAR takes this value only while building target and its prerequisites.
$@ The file name of the target of the current rule.
$< The name of the first prerequisite only.
$^ The names of all prerequisites, space separated, with duplicates removed.
$+ All prerequisites in listed order, keeping any duplicates, unlike $^.
$? The names of all prerequisites that are newer than the target.
$* The stem that % matched in a pattern rule; for foo.o built from %.o it is foo.
$(@D) The directory part of the target; $(@F) gives its file-name part.
$(wildcard *.c) Expand a shell glob to the list of file names that exist.
$(patsubst %.c,%.o,$(SRC)) Replace each word matching the first pattern with the second; here every .c becomes .o.
$(subst foo,bar,text) Replace every literal occurrence of foo with bar; plain text, no patterns.
$(filter %.c %.h,$(FILES)) Keep only the words that match one of the given patterns.
$(filter-out %.o,$(FILES)) Remove the words that match the patterns and keep the rest.
$(foreach v,$(LIST),$(v).o) Loop over each word in LIST as v and join the expanded results with spaces.
$(shell uname -s) Run a shell command while reading the makefile and substitute its output.
$(dir src/foo.c) Return the directory part of each name, including the trailing slash.
$(notdir src/foo.c) Return the file-name part of each name, dropping any directory.
$(basename src/foo.c) Remove the suffix from each name, leaving the path without its extension.
$(addprefix build/,$(OBJS)) Put the given prefix in front of each word in the list.
$(strip $(TEXT)) Remove leading, trailing, and repeated internal spaces from the text.
.PHONY: clean all Mark targets that are not real files so make always runs their recipes and never skips them.
.DEFAULT_GOAL := build Choose which target make builds with no arguments, overriding the first-target default.
.DELETE_ON_ERROR: Tell make to delete a target whose recipe fails partway, so no half-built file is left behind.
make -j4 Run up to four recipes in parallel to build faster.
make -n Dry run: print the commands make would run without actually running them.
<tab>@echo Building Start a recipe line with @ so make does not echo the command before running it.
<tab>-rm -f tmp Start a recipe line with - so make ignores a nonzero exit status and keeps going.
include config.mk Pull another makefile in at this point, as if its text were pasted here; -include ignores a missing file.
ifeq ($(OS),Windows_NT) Begin a conditional that make follows when the two values are equal; close it with endif.
ifdef DEBUG Begin a conditional that is true when the variable is defined; pair with else and endif.

Runs entirely in your browser. Nothing you type is sent anywhere; open DevTools and watch the Network tab to verify zero requests.

What this tool does

This is a searchable quick reference for GNU make, the build tool that reads a Makefile and figures out what to rebuild. It covers the pieces you reach for while writing a Makefile: rule headers and recipes, the different variable assignment flavors, the automatic variables like $@ and $<, the text and file-name functions, and the special targets and flags such as .PHONY and make -j. Each row pairs the exact syntax with a plain-English note on what it does. The whole list is built into the page, so it works offline and sends nothing anywhere.

How to use it

Start typing in the Filter box. Entering patsubst jumps straight to the pattern-substitution function; entering PHONY surfaces the phony-target syntax; entering %.o shows the pattern rules. The category buttons (Rules, Variables, Automatic vars, Functions, Phony and special) narrow the table to one area and combine with the text filter, so you can pick Automatic vars and type prereq to compare $<, $^, and $?. Clear the box to see the full sheet again.

Common use cases

  • Recalling which automatic variable holds the target versus the first prerequisite, like $@ against $<.
  • Deciding between =, :=, and ?= when you set a variable.
  • Writing a pattern rule such as %.o: %.c instead of one rule per file.
  • Looking up a text function like $(wildcard) or $(patsubst) to build a file list.
  • Remembering the flags for a quick check, such as make -n for a dry run.

Common pitfalls

  • Spaces instead of a tab. Every recipe line must begin with a real TAB character. Indent with spaces and make stops with a missing separator error, so set your editor to keep literal tabs in recipes.
  • Forgetting .PHONY. If a file named clean or test ever appears in the directory, make thinks the target is already up to date and skips it. Declare such labels with .PHONY so their recipes always run.
  • Using = when you meant :=. A recursively expanded variable is re-evaluated on every use, which can pull in values defined later or loop on itself. Reach for := when you want a value fixed at assignment time.
  • One dollar sign in a recipe. make consumes a single $ as the start of a variable reference, so to pass a literal dollar to the shell (for a shell variable, for example) you must write $$.

Frequently asked questions

What is a Makefile target?
A target is the thing a rule builds, usually a file name that appears before the colon in a rule header like app: main.o. When you run make app, make checks whether app is missing or older than its prerequisites and, if so, runs the recipe under the rule to rebuild it. A target can also be a label that is not a file, such as clean or test, in which case you mark it .PHONY so make always runs its recipe.
What is the difference between = and := in a Makefile?
VAR = value is recursively expanded: make re-expands the right-hand side every time you use VAR, so it can reference variables defined later in the file. VAR := value is simply expanded: make evaluates the right-hand side once, at the point of assignment, using only what is defined so far. Use := for predictable one-time values and to avoid accidental reference loops; use = when you deliberately want late binding.
What does $@ mean in a Makefile?
$@ is an automatic variable that holds the file name of the target being built by the current rule. Inside a recipe you can write it instead of repeating the target name, for example cc -o $@ $< builds the target from its first prerequisite. Automatic variables like $@, $<, and $^ only have a value inside a recipe, and they make pattern rules reusable because they adapt to whatever target is being built.
What is a .PHONY target?
A .PHONY target is one you declare as not corresponding to a real file, by listing it after .PHONY, such as .PHONY: clean. Normally make skips a target when a file of that name already exists and looks up to date, so a stray file called clean would stop make clean from running. Marking the target phony tells make to always run its recipe regardless of any like-named file, which is why clean, all, test, and install are usually phony.
Why does make require tabs and not spaces?
make treats recipe lines specially: every recipe line must begin with a real TAB character, and make uses that leading tab to tell recipe lines apart from the rest of the makefile syntax. If you indent with spaces instead, make reports an error like missing separator. The rule dates back to the original make and stays for compatibility, so configure your editor to keep a literal tab at the start of recipe lines rather than expanding it to spaces.
Does this cheat sheet run offline or send my searches anywhere?
It runs fully in your browser. The whole syntax list is baked into the page at build time and all searching and filtering happen locally in JavaScript, so nothing you type is sent to any server. Open your browser DevTools and watch the Network tab while you search to confirm there are zero requests.

Embed this tool

Free for any use; attribution appreciated. Paste this on your site:

The embed runs the same tool that lives at this URL. No tracking; no ads inside the embed. Resize height as needed for your layout.

Cite this tool

For academic, journalistic, or technical references. Pick a format:

Citations use 2026 as the publication year. Access date is left as a fillable placeholder where the citation style expects one.

Embedded tool from glunty.com