Makefile Reference
Free reference guide: Makefile Reference
About Makefile Reference
The Makefile Reference is a complete, searchable cheat sheet for GNU Make, covering every core concept developers need to write and maintain build automation scripts. The reference is organized into six focused categories: Targets (basic rules, .PHONY, .DEFAULT_GOAL), Variables (recursive =, simple :=, conditional ?=, appending +=), Pattern Rules (%, wildcard, patsubst, vpath), Functions (shell, foreach, filter, subst, strip, word), Conditionals (ifeq/ifneq, ifdef/ifndef, inline $(if)), and Automatic Variables ($@, $<, $^, $?, $*, $(@D)/$(@F)).
Software engineers, build system maintainers, embedded developers, and DevOps engineers rely on Makefiles to compile C/C++ projects, automate testing pipelines, manage Docker image builds, and coordinate multi-step deployment workflows. This reference is especially valuable when writing pattern rules for object file compilation, crafting conditional logic for cross-platform builds (Linux vs Windows), and using automatic variables to keep recipes DRY and maintainable.
Each entry provides the exact syntax, a plain-English description of what it does, and a realistic code example you can copy directly into a Makefile. The reference covers GNU Make conventions including the difference between recursive and simply-expanded variables, how vpath controls source file search directories, and when to prefer doReturn over thenReturn in spy scenarios. Whether you are writing your first Makefile or debugging a complex recursive build, this reference gives you immediate, accurate answers.
Key Features
- Six categories: Targets, Variables, Pattern Rules, Functions, Conditionals, Auto Variables
- All four variable assignment flavors: = (recursive), := (simple), ?= (conditional), += (append)
- Automatic variables $@, $<, $^, $?, $*, $(@D)/$(@F) with working examples
- Pattern rule syntax (%.o: %.c) and wildcard/patsubst file list manipulation
- Shell function integration for git hash, date stamping, and dynamic values
- ifeq/ifneq and ifdef/ifndef for cross-platform and debug/release conditional builds
- .PHONY declaration to prevent conflicts with same-named files in the project root
- Searchable interface — filter by category or keyword to jump straight to the rule you need
Frequently Asked Questions
What is the difference between = and := in Makefile variable assignment?
= creates a recursively-expanded variable, meaning the right-hand side is re-evaluated every time the variable is referenced. := creates a simply-expanded variable that is evaluated once at the point of definition. Use := when the value involves $(shell ...) calls or other expensive expansions you only want to run once.
What does .PHONY do in a Makefile?
.PHONY declares that a target name is not a real file. Without .PHONY, if a file named "clean" or "test" exists in the directory, Make will think the target is already up-to-date and skip it. Listing your non-file targets under .PHONY ensures they always run when invoked.
What is the automatic variable $@ in Makefile?
$@ expands to the filename of the current rule's target. In the recipe "gcc -o $@ $^", $@ is replaced with the target name (e.g., app or build/main.o), making recipes reusable across pattern rules and avoiding hardcoded output filenames.
How does the pattern rule %.o: %.c work?
The % wildcard acts as a stem that matches any non-empty string. When Make needs to build main.o, it matches the pattern %.o: %.c and substitutes "main" for %, knowing it should compile main.c to produce main.o. This eliminates the need to write a separate rule for every source file.
What is the difference between $^ and $< in automatic variables?
$< expands to only the first prerequisite, which is useful in compilation rules where you compile a single source file. $^ expands to all prerequisites (with duplicates removed), which is useful in link rules where you need to pass every object file to the linker.
How do I use $(shell ...) in a Makefile?
$(shell command) executes the shell command and substitutes its output as a Make variable value. Common uses include capturing git commit hashes ($(shell git rev-parse --short HEAD)) and build dates ($(shell date +%F)). Assign the result with := to avoid re-running the shell command on every reference.
When should I use ifeq vs ifdef in a Makefile?
Use ifeq ($(VAR), value) when you need to compare the variable's value to a specific string — for example, checking if OS is Windows_NT. Use ifdef VAR when you only need to know whether the variable is defined at all, regardless of its value — for example, checking if DEBUG is set without caring what value it holds.
What is .DEFAULT_GOAL in a Makefile?
.DEFAULT_GOAL sets which target Make runs when you invoke make without specifying a target. By convention, the first target in the file is the default, but setting .DEFAULT_GOAL := help makes the help target run by default, which is a common pattern for self-documenting Makefiles in large projects.