skills/makefile-patterns/SKILL.md
Makefile patterns for development workflows. Use when creating or understanding Makefiles for build automation, release workflows, and development iteration.
npx skillsauth add thrashr888/thrashr888-agent-kit makefile-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Common Makefile patterns for development, building, testing, and releasing.
# Variables at top
PROJECT := myproject
VERSION := $(shell cat VERSION 2>/dev/null || echo "0.0.0")
BUILD_DIR := ./build
# Default target (first target)
.PHONY: help
help:
@echo "Available targets:"
@echo " build - Build the project"
@echo " test - Run tests"
@echo " clean - Clean build artifacts"
# Actual targets
.PHONY: build test clean
build:
@echo "Building $(PROJECT) $(VERSION)..."
test:
@echo "Running tests..."
clean:
rm -rf $(BUILD_DIR)
# Use env var if set, otherwise default
CONFIG ?= Release
PORT ?= 8080
# Computed from shell
VERSION := $(shell git describe --tags --always 2>/dev/null || echo "dev")
GIT_SHA := $(shell git rev-parse --short HEAD)
BUILD_TIME := $(shell date -u +%Y%m%dT%H%M%SZ)
# Platform-specific
ifeq ($(shell uname),Darwin)
OS := macos
SED := sed -i ''
else
OS := linux
SED := sed -i
endif
.PHONY: help
help:
@echo "Development:"
@echo " dev - Start development server"
@echo " build - Build for production"
@echo " test - Run tests"
@echo ""
@echo "Release:"
@echo " release - Full release workflow"
@echo " tag - Create git tag"
@echo ""
@echo "Utilities:"
@echo " clean - Clean build artifacts"
@echo " version - Show current version"
.PHONY: help
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
build: ## Build the project
...
test: ## Run tests
...
APP_NAME := MyApp
APP := $(BUILD_DIR)/$(APP_NAME).app
.PHONY: dev kill run
dev: kill build run ## Quick dev iteration
kill: ## Stop running app
@echo "Stopping $(APP_NAME)..."
@pkill -x "$(APP_NAME)" 2>/dev/null || true
@sleep 0.5
run: ## Run the app
@echo "Starting $(APP_NAME)..."
@open $(APP)
.PHONY: watch
watch: ## Watch for changes and rebuild
@echo "Watching for changes..."
@fswatch -o src/ | xargs -n1 -I{} make build
.PHONY: build build-release
build: ## Debug build
cargo build
build-release: ## Release build
cargo build --release
check: ## Fast syntax check
cargo check
fmt: ## Format code
cargo fmt
lint: ## Lint with clippy
cargo clippy -- -D warnings
test: ## Run tests
cargo test
# Quality gate (run before commits)
.PHONY: qa
qa: fmt lint test ## Run all quality checks
DEVELOPER_DIR ?= /Applications/Xcode.app/Contents/Developer
PROJECT := ./MyApp.xcodeproj
SCHEME := MyApp
CONFIG ?= Debug
BUILD_DIR := ./build
DEST := platform=macOS
.PHONY: build
build: deps ## Build the app
DEVELOPER_DIR=$(DEVELOPER_DIR) xcodebuild -project $(PROJECT) \
-scheme $(SCHEME) -configuration $(CONFIG) \
-derivedDataPath $(BUILD_DIR) -destination '$(DEST)' \
build | cat
deps: ## Resolve dependencies
DEVELOPER_DIR=$(DEVELOPER_DIR) xcodebuild -resolvePackageDependencies \
-project $(PROJECT) | cat
archive: ## Create release archive
DEVELOPER_DIR=$(DEVELOPER_DIR) xcodebuild -project $(PROJECT) \
-scheme $(SCHEME) -configuration Release \
-archivePath $(BUILD_DIR)/$(SCHEME).xcarchive \
archive | cat
.PHONY: install test lint fmt
install: ## Install dependencies
uv sync --dev
test: ## Run tests
uv run pytest
lint: ## Run linter
uv run ruff check .
fmt: ## Format code
uv run black .
uv run isort .
DMG_NAME := MyApp
DMG_DIR := $(BUILD_DIR)/dmg
DMG_FILE := $(BUILD_DIR)/$(DMG_NAME).dmg
EXPORTED_APP := $(HOME)/Downloads/MyApp.app
.PHONY: dmg
dmg: ## Create DMG installer
@test -d "$(EXPORTED_APP)" || \
(echo "Error: Export app from Xcode first" && exit 1)
rm -rf $(DMG_DIR) $(DMG_FILE)
mkdir -p $(DMG_DIR)
cp -R $(EXPORTED_APP) $(DMG_DIR)/
create-dmg \
--volname "$(DMG_NAME)" \
--window-pos 200 120 \
--window-size 600 400 \
--icon-size 100 \
--icon "MyApp.app" 150 190 \
--app-drop-link 450 190 \
$(DMG_FILE) $(DMG_DIR)
SHA256_FILE := $(BUILD_DIR)/MyApp.dmg.sha256
S3_BUCKET := my-bucket
.PHONY: sha256 upload
sha256: dmg ## Generate SHA256
shasum -a 256 $(DMG_FILE) | awk '{print $$1}' > $(SHA256_FILE)
@echo "SHA256: $$(cat $(SHA256_FILE))"
upload: sha256 ## Upload to S3
aws s3 cp $(DMG_FILE) s3://$(S3_BUCKET)/downloads/$(VERSION)/MyApp.dmg --acl public-read
aws s3 cp $(SHA256_FILE) s3://$(S3_BUCKET)/downloads/$(VERSION)/MyApp.dmg.sha256 --acl public-read
HOMEBREW_TAP := $(HOME)/Workspace/homebrew-myapp
.PHONY: brew-update
brew-update: sha256 ## Update Homebrew tap
@test -d "$(HOMEBREW_TAP)" || (echo "Error: Tap not found" && exit 1)
@SHA=$$(cat $(SHA256_FILE)) && \
$(SED) "s/version \".*\"/version \"$(VERSION)\"/" $(HOMEBREW_TAP)/Casks/myapp.rb && \
$(SED) "s/sha256 \".*\"/sha256 \"$$SHA\"/" $(HOMEBREW_TAP)/Casks/myapp.rb
@echo "Updated tap to $(VERSION)"
.PHONY: tag
tag: ## Create git tag
@if git rev-parse "v$(VERSION)" >/dev/null 2>&1; then \
echo "Tag v$(VERSION) already exists"; \
else \
git tag -a "v$(VERSION)" -m "Release $(VERSION)" && \
echo "Created tag v$(VERSION)"; \
fi
.PHONY: release
release: upload brew-update ## Full release workflow
@echo ""
@echo "=== Release $(VERSION) complete ==="
@echo "Next steps:"
@echo " 1. git commit -m 'Release $(VERSION)' && git push"
@echo " 2. make tag && git push --tags"
@echo " 3. cd $(HOMEBREW_TAP) && git commit -m 'Update to $(VERSION)' && git push"
.PHONY: check-aws
check-aws: ## Verify AWS credentials
@aws sts get-caller-identity > /dev/null 2>&1 || \
(echo "Error: AWS not configured. Run 'aws configure'" && exit 1)
@echo "AWS credentials OK"
.PHONY: version
version: ## Show current version
@echo "Version: $(VERSION)"
@echo "Git SHA: $(GIT_SHA)"
@echo "Build: $(BUILD_TIME)"
.PHONY: clean clean-all
clean: ## Clean build artifacts
rm -rf $(BUILD_DIR)
clean-all: clean ## Clean everything including dependencies
rm -rf node_modules .venv __pycache__
DON'T:
.PHONY for non-file targetscd without && (each line runs in new shell)DO:
?= for overridable defaults| cat to Xcode commands (prevents xcpretty issues)@ prefix to hide command echo when appropriatedevelopment
Generate standardized project documentation using the 5-style system. Use when asked to create plans, specs, skills, RFCs, ADRs, or other project documentation. Ensures consistent, high-quality documentation across the codebase.
tools
Release workflow for Rust CLI tools with multi-platform binaries, GitHub Releases, and Homebrew distribution. Use when releasing a new version of a Rust project.
tools
Onboard a new Rust project with standard tooling, CI/CD, and best practices. Use when starting a new Rust project or setting up an existing one with proper infrastructure.
development
Rust development workflow with quality gates, testing, and iteration patterns. Use when developing Rust code, running tests, or iterating on Rust projects.