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 default target
make

# Run make using the default makefile and first target.

Build a specific target
make test

# Run a named target from the makefile.

Use a specific makefile
make -f build/Makefile deploy

# Choose a file other than the default makefile names.

Run make in another directory
make -C services/api test

# Change directory before reading the makefile.

Parallel build
make -j8

# Build using multiple jobs.

Dry run
make -n deploy

# Print commands without executing them.

Touch targets only
make -t

# Mark targets as updated without running recipes.

Question mode
make -q

# Exit status indicates whether anything is out of date.

Trace recursive directories
make --print-directory -C app test

# Show enter/leave directory messages.

Enable debug output
make --debug=b

# Print internal decision-making details.

Warn on undefined variables
make --warn-undefined-variables

# Emit warnings when undefined variables are expanded.

Print database
make -p -n

# Dump parsed rules and variables.

## Targets, prerequisites, and recipes
Basic rule
build/app: main.o util.o
  cc -o build/app main.o util.o

# Define a target, prerequisites, and recipe.

Rule with multiple prerequisites
bundle.js: app.js ui.js api.js
  cat $^ > $@

# Rebuild target when any listed prerequisite changes.

Phony target
.PHONY: test

test:
  pytest -q

# Create a target that does not represent a file.

Multiple targets one recipe
.PHONY: lint fmt
lint fmt:
  pnpm biome check .

# Attach the same recipe to multiple targets.

Order-only prerequisite
dist/app.js: src/app.js | dist
  cp $< $@

dist:
  mkdir -p dist

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

Stamp file target
node_modules/.stamp: package-lock.json
  npm ci
  touch $@

# Track completion of a step using a timestamp file.

Clean target
.PHONY: clean
clean:
  rm -rf dist build *.o

# Remove build artifacts.

Set explicit default goal
.DEFAULT_GOAL := help

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

## Variables and assignment
Recursive variable
SRC = $(wildcard src/*.c)

# Expand later when used.

Simple variable
CURDIR_ABS := $(shell pwd)

# Expand immediately at assignment time.

Append to variable
CFLAGS += -Wall -Wextra

# Add text to an existing variable.

Set if undefined
ENV ?= dev

# Assign only if variable is not already set.

Override from command line
make IMAGE_TAG=2026.03.06 deploy

# Pass variable values when invoking make.

Force override in makefile
override CFLAGS += -g

# Override even a command-line assignment.

Export variable to recipes
export AWS_PROFILE := prod-admin

# Pass a variable into the shell environment of recipe commands.

Stop exporting a variable
unexport DEBUG

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

Inspect variable origin
$(info CC came from $(origin CC))

# See where a variable value came from.

Inspect variable flavor
$(info CFLAGS flavor: $(flavor CFLAGS))

# Check whether a variable is recursive or simple.

## Includes and conditionals
Include another makefile
include config.mk rules/*.mk

# Read another file while parsing.

Optional include
-include .env.mk

# Ignore missing include files.

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

# Branch based on string equality.

ifdef conditional
ifdef CI
  TEST_FLAGS += --maxfail=1
endif

# Check whether a variable is defined.

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

# Branch based on operating system or shell-provided variables.

## Special targets and behavior control
Declare multiple phony targets
.PHONY: all clean test lint format help

# Mark non-file targets explicitly.

Silent recipes
.SILENT:
# or prefix a line with @

# Suppress command echoing globally or per line.

Delete target on error
.DELETE_ON_ERROR:

# Remove a partially built target if the recipe fails.

One shell per recipe
.ONESHELL:

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

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

Secondary expansion
.SECONDEXPANSION:

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

# Allow a second variable expansion for prerequisites.

Disable parallelism
.NOTPARALLEL:

# Force serial execution for all or selected targets.

Recommended next

No recommendations yet.