# make — Automate Builds with Makefiles

> Practical guide to GNU Make: targets, prerequisites and recipes in Makefiles – build automation and a general-purpose task runner for any project.

Source: https://www.jpkc.com/db/en/cheatsheets/build-languages/make/

<!-- PROSE:intro -->
GNU Make is the classic build-automation tool: it reads a Makefile and uses file timestamps to decide which targets need rebuilding. Every rule consists of a target, its prerequisites (dependencies) and a recipe – the shell commands that produce the target. Crucially, recipe lines must begin with a real tab character, never spaces, or Make aborts with "missing separator". Long past being a C/C++-only tool, Make works as a general-purpose task runner for almost any project.
<!-- PROSE:intro:end -->

## Running Make

`make` — Run the first (default) target in the Makefile.

```bash
make
```

`make <target>` — Run a specific target.

```bash
make build
```

`make -f <file>` — Use a specific Makefile instead of the default.

```bash
make -f Makefile.prod build
```

`make -n` — Dry run: print commands that would be executed without running them.

```bash
make -n deploy
```

`make -j <n>` — Run up to n jobs in parallel for faster builds.

```bash
make -j$(nproc)
```

`make -j` — Run unlimited parallel jobs (use with caution).

```bash
make -j
```

`make -B` — Unconditionally build all targets (force rebuild).

```bash
make -B
```

`make -s` — Silent mode: do not print the commands as they are executed.

```bash
make -s build
```

`make -k` — Keep going: continue building other targets even if one fails.

```bash
make -k test
```

`make -C <directory>` — Change to directory before reading the Makefile.

```bash
make -C src/ build
```

`make VAR=value` — Override a variable on the command line.

```bash
make CC=clang build
```

## Makefile Basics

`target: prerequisites` — Basic rule: target depends on prerequisites, built by the recipe. Recipe lines MUST start with a tab.

```makefile
build: main.o utils.o
	gcc -o app main.o utils.o
```

`VAR = value` — Recursively expanded variable (re-evaluated on each use).

```makefile
CC = gcc
CFLAGS = -Wall -O2
```

`VAR := value` — Simply expanded variable (evaluated once at assignment time).

```makefile
DATE := $(shell date +%Y%m%d)
```

`VAR ?= value` — Set variable only if it is not already defined.

```makefile
PREFIX ?= /usr/local
```

`VAR += value` — Append to an existing variable.

```makefile
CFLAGS += -g
```

`export VAR` — Export a variable to sub-make processes and recipe shells.

```makefile
export PATH := $(PWD)/bin:$(PATH)
```

## Automatic Variables

`$@` — The target name of the current rule.

```makefile
build:
	echo "Building $@"
```

`$<` — The first prerequisite.

```makefile
%.o: %.c
	$(CC) -c $< -o $@
```

`$^` — All prerequisites (with duplicates removed).

```makefile
app: main.o utils.o
	$(CC) -o $@ $^
```

`$?` — All prerequisites that are newer than the target.

```makefile
lib.a: a.o b.o
	ar rcs $@ $?
```

`$*` — The stem matched by a pattern rule (% part).

```makefile
%.o: %.c
	echo "Compiling $*"
```

`$(@D) / $(@F)` — The directory / filename part of the target.

```makefile
build/%.o: src/%.c
	mkdir -p $(@D)
	$(CC) -c $< -o $@
```

## Pattern Rules & Wildcards

`%.o: %.c` — Pattern rule: build any .o file from its corresponding .c file.

```makefile
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@
```

`$(wildcard <pattern>)` — Expand a glob pattern to matching filenames.

```makefile
SOURCES := $(wildcard src/*.c)
```

`$(patsubst <from>,<to>,<text>)` — Replace pattern in a list of words.

```makefile
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
```

`$(SOURCES:.c=.o)` — Substitution reference: shorthand for patsubst.

```makefile
OBJECTS := $(SOURCES:.c=.o)
```

`$(filter <pattern>,<text>)` — Keep only words matching the pattern.

```makefile
C_FILES := $(filter %.c,$(ALL_FILES))
```

`$(filter-out <pattern>,<text>)` — Remove words matching the pattern.

```makefile
SOURCES := $(filter-out test_%,$(ALL_SOURCES))
```

## Functions

`$(shell <command>)` — Execute a shell command and capture its output.

```makefile
GIT_HASH := $(shell git rev-parse --short HEAD)
```

`$(info <text>)` — Print an informational message during Makefile parsing.

```makefile
$(info Building version $(VERSION))
```

`$(warning <text>)` — Print a warning message (includes file and line number).

```makefile
$(warning CC is set to $(CC))
```

`$(error <text>)` — Print an error message and stop execution.

```makefile
ifndef CONFIG
$(error CONFIG is not set)
endif
```

`$(foreach var,list,body)` — Loop: evaluate body for each word in list.

```makefile
$(foreach dir,src lib test,$(wildcard $(dir)/*.c))
```

`$(if condition,then,else)` — Conditional function: return then if condition is non-empty.

```makefile
FLAGS := $(if $(DEBUG),-g -O0,-O2)
```

`$(call func,arg1,arg2)` — Call a user-defined function (multi-line macro).

```makefile
define compile
	$(CC) $(CFLAGS) -c $(1) -o $(2)
endef

%.o: %.c
	$(call compile,$<,$@)
```

## Conditionals

`ifeq ($(VAR),value) … endif` — Conditional block: execute if variable equals value.

```makefile
ifeq ($(OS),Linux)
CFLAGS += -DLINUX
endif
```

`ifneq ($(VAR),value) … endif` — Conditional block: execute if variable does NOT equal value.

```makefile
ifneq ($(DEBUG),)
CFLAGS += -g
endif
```

`ifdef VAR … endif` — Conditional block: execute if variable is defined.

```makefile
ifdef VERBOSE
Q :=
else
Q := @
endif
```

`ifndef VAR … endif` — Conditional block: execute if variable is NOT defined.

```makefile
ifndef CC
CC := gcc
endif
```

## Special Targets & Directives

`.PHONY: <targets>` — Declare targets that are not actual files (always run).

```makefile
.PHONY: all build clean test deploy
```

`.DEFAULT_GOAL := <target>` — Set the default target if none is specified on the command line.

```makefile
.DEFAULT_GOAL := build
```

`.SILENT: <targets>` — Do not print recipes for the specified targets.

```makefile
.SILENT: help
```

`include <file>` — Include another Makefile (error if not found).

```makefile
include config.mk
```

`-include <file>` — Include another Makefile (silently ignore if not found).

```makefile
-include .env.mk
```

`@<command>` — Prefix a recipe line with @ to suppress printing the command.

```makefile
help:
	@echo "Available targets: build, test, clean"
```

`-<command>` — Prefix with - to ignore errors from this command.

```makefile
clean:
	-rm -f *.o app
```

## Common Makefile Patterns

`all: build` — Convention: 'all' target builds everything.

```makefile
all: build docs
```

`clean:` — Convention: 'clean' removes build artifacts.

```makefile
.PHONY: clean
clean:
	rm -rf build/ dist/
```

`install:` — Convention: 'install' copies built files to system directories.

```makefile
install: build
	install -m 755 app $(PREFIX)/bin/
```

`test:` — Convention: 'test' runs the test suite.

```makefile
.PHONY: test
test:
	go test ./...
```

`help:` — Self-documenting help target: extracts ## comments from targets.

```makefile
build: ## Build the application
	go build -o app

help: ## Show this help
	@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | sort | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "  %-20s %s\n", $$1, $$2}'
```

<!-- PROSE:outro -->
## Conclusion

Make has been the Unix and Linux standard for build automation for decades, and despite a wave of newer build tools it remains ubiquitous. Once you grasp the three core building blocks – targets, prerequisites and recipes – you can use Make for almost any repetitive task, not just compiling C code. Mind the infamous tab requirement in recipe lines and declare any target that doesn't produce a file with `.PHONY`. Do that and your Makefile stays robust, portable and easy for collaborators and AI systems alike to follow.

## Further Reading

- [GNU Make Manual](https://www.gnu.org/software/make/manual/) – official reference for every function and directive
- [Make – Wikipedia](https://en.wikipedia.org/wiki/Make_(software)) – overview of history, concepts and variants
<!-- PROSE:outro:end -->

## Related Commands

- [artisan](https://www.jpkc.com/db/en/cheatsheets/build-languages/artisan/) – command-line tool of the Laravel framework
- [cargo](https://www.jpkc.com/db/en/cheatsheets/build-languages/cargo/) – build system and package manager for Rust
- [composer](https://www.jpkc.com/db/en/cheatsheets/build-languages/composer/) – dependency manager for PHP projects

