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.