| name | makefile |
| description | GNU Make automation and build system guidance. Use when creating or maintaining Makefiles, writing Make targets and recipes, or configuring GNU Make build automation. Keywords: Makefile, GNU Make, targets, recipes, build automation. |
| metadata | {"version":"2.0.0","release_date":"2023-02-26"} |
Makefile Skill
Guidance for creating and maintaining GNU Make build automation.
Quick Navigation
Core Concepts
Rule Structure
target: prerequisites
recipe
Critical: Recipe lines MUST start with TAB character.
File vs Phony Targets
build/app.o: src/app.c
$(CC) -c $< -o $@
.PHONY: clean test install
clean:
rm -rf build/
Variable Assignment
| Operator | Name | When Expanded |
|---|
:= | Simple | Once, at definition |
?= | Conditional | If not already set |
= | Recursive | Each use (late binding) |
+= | Append | Adds to existing value |
CC := gcc
CFLAGS ?= -O2
DEBUG = $(VERBOSE)
CFLAGS += -Wall
Automatic Variables
| Variable | Meaning |
|---|
$@ | Target |
$< | First prerequisite |
$^ | All prerequisites (unique) |
$? | Prerequisites newer than target |
$* | Stem in pattern rules |
Essential Patterns
Self-Documenting Help
.DEFAULT_GOAL := help
help: ## Show available targets
@grep -E '^[a-zA-Z_-]+:.*?
awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}'
install: ## Install dependencies
uv sync
test: ## Run tests
uv run pytest
Platform Detection
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
OPEN := open
else ifeq ($(UNAME_S),Linux)
OPEN := xdg-open
endif
Build Directory
BUILDDIR := build
SOURCES := $(wildcard src/*.c)
OBJECTS := $(patsubst src/%.c,$(BUILDDIR)/%.o,$(SOURCES))
$(BUILDDIR)/%.o: src/%.c | $(BUILDDIR)
$(CC) -c $< -o $@
$(BUILDDIR):
mkdir -p $@
Environment Export
export PYTHONPATH := $(PWD)/src
export DATABASE_URL
test:
pytest tests/
Common Targets
Quality Checks
.PHONY: lint format check test
lint: ## Run linters
ruff check .
mypy src/
format: ## Format code
ruff format .
check: format lint test ## All quality checks
Cleanup
.PHONY: clean clean-all
clean: ## Remove build artifacts
rm -rf build/ dist/ *.egg-info
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
clean-all: clean ## Remove all generated files
rm -rf .venv .pytest_cache .mypy_cache
Docker Integration
IMAGE := myapp
VERSION := $(shell git describe --tags --always)
docker-build: ## Build Docker image
docker build -t $(IMAGE):$(VERSION) .
docker-run: ## Run container
docker run -d -p 8000:8000 $(IMAGE):$(VERSION)
Recipe Execution
Each Line = Separate Shell
bad:
cd subdir
pwd
good:
cd subdir && pwd
also-good:
cd subdir && \
pwd && \
make
Silent and Error Handling
target:
@echo "@ suppresses command echo"
-rm -f maybe.txt
Parallel Execution
make -j4
make -j4 lint test
Output Discipline
One line in, one line out. Avoid echo spam.
start:
@echo "Starting services..."
docker compose up -d
@echo "Waiting..."
@sleep 3
@echo "Done!"
start: ## Start services
@echo "Starting at http://localhost:8000 ..."
@docker compose up -d
@echo "Logs: docker compose logs -f"
Conditionals
DEBUG ?= 0
ifeq ($(DEBUG),1)
CFLAGS += -g -O0
else
CFLAGS += -O2
endif
ifdef CI
TEST_FLAGS := --ci
endif
Including Files
include config.mk
-include local.mk
-include .env
Common Pitfalls
| Pitfall | Problem | Solution |
|---|
| Spaces in recipes | Recipes need TAB | Use actual TAB character |
| Missing .PHONY | make test fails if test file exists | Declare .PHONY: test |
| cd in recipes | Each line is new shell | Use cd dir && command |
= vs := confusion | Unexpected late expansion | Use := by default |
| Unexported vars | Subprocesses don't see vars | export VAR |
| Complex shell in make | Hard to maintain | Move to external script |
Quick Reference
.DEFAULT_GOAL := help
SHELL := /bin/bash
.SHELLFLAGS := -ec
.PHONY: help install test lint format clean
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?
awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}'
install: ## Install dependencies
uv sync --extra dev
test: ## Run tests
uv run pytest tests/ -v
lint: ## Run linters
uv run ruff check .
format: ## Format code
uv run ruff format .
clean: ## Clean artifacts
rm -rf build/ dist/ .pytest_cache
Links
See Also