Makefile Cheat Sheet

Comprehensive GNU make and Makefile reference covering targets, prerequisites, recipes, variables, includes, conditionals, pattern rules, and command-line usage.

View
StandardDetailedCompact
Export
Copy the compact sheet, download it, or print it.
Download
`D` dense toggle · `C` copy all

Core make commands

Run make, choose files, select targets, and control execution.

Run default target

Run make using the default makefile and first target.

bashANYclidefaultbuild
bash
make

Reads `GNUmakefile`, `makefile`, or `Makefile` and builds the default goal.

Build a specific target

Run a named target from the makefile.

bashANYclitarget
bash
make test

Builds or executes the recipe for target `test`.

Use a specific makefile

Choose a file other than the default makefile names.

bashANYclimakefilefile
bash
make -f build/Makefile deploy

Use `-f` to point make at a specific file.

Run make in another directory

Change directory before reading the makefile.

bashANYclidirectory
bash
make -C services/api test

Useful in monorepos and wrapper scripts.

Parallel build

Build using multiple jobs.

bashANYcliparalleljobs
bash
make -j8

Allows multiple recipes to run in parallel when dependencies permit.

Dry run

Print commands without executing them.

bashANYclidry-rundebug
bash
make -n deploy

Great for inspecting what a target would do.

Touch targets only

Mark targets as updated without running recipes.

bashANYclitouch
bash
make -t

Useful for recovery and dependency graph alignment.

Question mode

Exit status indicates whether anything is out of date.

bashANYcliquestionci
bash
make -q

Handy in CI checks or wrapper scripts.

Trace recursive directories

Show enter/leave directory messages.

bashANYclirecursivedebug
bash
make --print-directory -C app test

Useful when debugging recursive make.

Enable debug output

Print internal decision-making details.

bashANYclidebugdiagnostics
bash
make --debug=b

GNU make supports several debug modes such as `a`, `b`, `v`, `i`, `j`, and `m`.

Warn on undefined variables

Emit warnings when undefined variables are expanded.

bashANYclivariablesdebug
bash
make --warn-undefined-variables

Very useful in large makefiles with many variables.

Print database

Dump parsed rules and variables.

bashANYclidatabasedebug
bash
make -p -n

Shows built-in rules, variables, and parsed state.

Targets, prerequisites, and recipes

Core makefile structure and everyday patterns.

Basic rule

Define a target, prerequisites, and recipe.

makefileANYrulestargetrecipe
makefile
build/app: main.o util.o
  cc -o build/app main.o util.o

A rule maps a target to prerequisites and the commands needed to update it.

Rule with multiple prerequisites

Rebuild target when any listed prerequisite changes.

makefileANYrulesprerequisitesautomatic-variables
makefile
bundle.js: app.js ui.js api.js
  cat $^ > $@

`$^` expands to all prerequisites and `$@` to the target name within the recipe.

Phony target

Create a target that does not represent a file.

makefileANYphonytarget
makefile
.PHONY: test

test:
  pytest -q

Use phony targets for commands like `test`, `clean`, and `deploy`.

Multiple targets one recipe

Attach the same recipe to multiple targets.

makefileANYrulesmultiple-targets
makefile
.PHONY: lint fmt
lint fmt:
  pnpm biome check .

Useful when several targets truly run the same command.

Order-only prerequisite

Require creation order without forcing rebuilds when the prerequisite timestamp changes.

makefileANYprerequisitesorder-onlydirectories
makefile
dist/app.js: src/app.js | dist
  cp $< $@

dist:
  mkdir -p dist

Prerequisites after `|` enforce order only.

Stamp file target

Track completion of a step using a timestamp file.

makefileANYstampdependenciesci
makefile
node_modules/.stamp: package-lock.json
  npm ci
  touch $@

A stamp file is often cleaner than making a phony install target rerun every time.

Clean target

Remove build artifacts.

makefileANYcleanphony
makefile
.PHONY: clean
clean:
  rm -rf dist build *.o

Classic maintenance target.

Set explicit default goal

Choose which target runs when the user invokes plain `make`.

makefileANYdefault-goalspecial-targets
makefile
.DEFAULT_GOAL := help

Clearer than relying on the first target in the file.

Variables and assignment

Recursive, simple, conditional, and shell-expanded variables.

Recursive variable

Expand later when used.

makefileANYvariablesassignment
makefile
SRC = $(wildcard src/*.c)

`=` creates a recursively expanded variable.

Simple variable

Expand immediately at assignment time.

makefileANYvariablesassignmentsimple
makefile
CURDIR_ABS := $(shell pwd)

`:=` is useful when you want shell commands or functions evaluated once.

Append to variable

Add text to an existing variable.

makefileANYvariablesappend
makefile
CFLAGS += -Wall -Wextra

Works with both recursive and simple variables.

Set if undefined

Assign only if variable is not already set.

makefileANYvariablesconditional
makefile
ENV ?= dev

Often used with environment overrides like `make ENV=prod deploy`.

Override from command line

Pass variable values when invoking make.

bashANYvariablesclioverride
bash
make IMAGE_TAG=2026.03.06 deploy

Command-line variables override normal makefile assignments.

Force override in makefile

Override even a command-line assignment.

makefileANYvariablesoverride
makefile
override CFLAGS += -g

Use sparingly when the makefile must enforce a setting.

Export variable to recipes

Pass a variable into the shell environment of recipe commands.

makefileANYvariablesexportenvironment
makefile
export AWS_PROFILE := prod-admin

Exported variables are inherited by recipe shells and recursive make invocations.

Stop exporting a variable

Prevent a variable from propagating to recipes and sub-makes.

makefileANYvariablesunexportenvironment
makefile
unexport DEBUG

Useful when a parent environment leaks unwanted values.

Inspect variable origin

See where a variable value came from.

makefileANYvariablesdiagnostics
makefile
$(info CC came from $(origin CC))

Origins include `default`, `environment`, `file`, `command line`, and more.

Inspect variable flavor

Check whether a variable is recursive or simple.

makefileANYvariablesdiagnostics
makefile
$(info CFLAGS flavor: $(flavor CFLAGS))

Useful when debugging unexpected expansions.

Includes and conditionals

Split makefiles and branch on environment or platform.

Include another makefile

Read another file while parsing.

makefileANYincludemodularity
makefile
include config.mk rules/*.mk

`include` is excellent for shared project fragments.

Optional include

Ignore missing include files.

makefileANYincludeoptional
makefile
-include .env.mk

Common for generated dependency files and local overrides.

ifeq conditional

Branch based on string equality.

makefileANYconditionalsifeq
makefile
ifeq ($(ENV),prod)
  API_URL := https://api.example.com
else
  API_URL := https://api.dev.example.com
endif

GNU make conditionals run during parsing, not execution.

ifdef conditional

Check whether a variable is defined.

makefileANYconditionalsifdef
makefile
ifdef CI
  TEST_FLAGS += --maxfail=1
endif

Useful for CI-vs-local behavior.

OS-specific include

Branch based on operating system or shell-provided variables.

makefileANYconditionalsplatform
makefile
ifeq ($(OS),Windows_NT)
  RM := del /Q
else
  RM := rm -f
endif

Portable projects often branch on Windows vs Unix-like behavior.

Special targets and behavior control

Targets that alter how make interprets rules and files.

Declare multiple phony targets

Mark non-file targets explicitly.

makefileANYspecial-targetsphony
makefile
.PHONY: all clean test lint format help

Prevents file name collisions and speeds make slightly by skipping implicit rule search.

Silent recipes

Suppress command echoing globally or per line.

makefileANYspecial-targetssilent
makefile
.SILENT:
# or prefix a line with @

Silence all recipes or use `@command` for individual lines.

Delete target on error

Remove a partially built target if the recipe fails.

makefileANYspecial-targetserrors
makefile
.DELETE_ON_ERROR:

Helpful for avoiding corrupt output files after failures.

One shell per recipe

Run all lines of a recipe in a single shell instance.

makefileANYspecial-targetsshell
makefile
.ONESHELL:

deploy:
  set -eu
  cd infra
  terraform apply -auto-approve

Without `.ONESHELL`, each recipe line runs in a separate shell.

Secondary expansion

Allow a second variable expansion for prerequisites.

makefileANYspecial-targetsexpansionadvanced
makefile
.SECONDEXPANSION:

$(OUT_DIR)/%.o: $$(SRC_DIR)/%.c
  cc -c $< -o $@

Advanced GNU make feature used with dynamic prerequisite lists.

Disable parallelism

Force serial execution for all or selected targets.

makefileANYspecial-targetsparallel
makefile
.NOTPARALLEL:

Useful for non-parallel-safe recipes.

Recommended next

No recommendations yet.