← All cheatsheets

Build

Makefile — the patterns that work for small projects

## Basic target
```make
build:
\tgo build -o bin/app ./cmd/app
```
Targets indented with TAB (not spaces). Hard rule.

## .PHONY (target is not a file)
```make
.PHONY: build test clean
```
Always declare task targets as PHONY or Make may skip them.

## Variables
```make
BINARY := bin/app
SRC := $(wildcard cmd/**/*.go)

build: $(BINARY)

$(BINARY): $(SRC)
\tgo build -o $@ ./cmd/app
```

## Help target (showing all available)
```make
.PHONY: help
help: ## Show this help
\t@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk -F':.*?## ' '{printf "  %-20s %s\n", $$1, $$2}'

build: ## Compile the app
\tgo build -o bin/app

test: ## Run tests
\tgo test ./...
```
Run `make help` and see all targets with descriptions.

## Conditional + env
```make
ENV ?= dev

deploy:
ifeq ($(ENV),prod)
\t@echo "Deploying to prod"
else
\t@echo "Deploying to dev"
endif
```

## Pattern rule
```make
%.html: %.md
\tpandoc $< -o $@
```
`make report.html` runs pandoc on report.md.

## Common gotcha
- Each line of a recipe runs in its own subshell. `cd dir` then `make-thing` in next line doesn't carry the dir. Chain with `&&` or use `.ONESHELL:`.
- Variables: `=` is lazy/recursive, `:=` is immediate. Use `:=` unless you specifically want recursion.