creating-makefile
Scaffold or review Makefiles following org conventions. Use when creating a new Makefile, auditing an existing one, or adding recipes to a project. Auto-detects project type from the working directory
SKILL.mdplugins/makefile-core/skills/creating-makefile/SKILL.md
GitHubCreating Makefiles
Target: $ARGUMENTS
Creates or reviews a rigorous, consistent Makefile following org conventions.
References
- Required structure + patterns:
references/makefile-conventions.md - CI linter script:
references/lint-makefile.sh - Language-specific recipe templates:
references/scaffold-*.md
Required Structure (all project types)
Every Makefile must have these elements in order:
# Header comment describing the project
# Run `make` to see all available recipes.
# GNU Make version guard
ifeq ($(filter oneshell,$(.FEATURES)),)
$(error GNU Make >= 3.82 required (.ONESHELL). macOS ships 3.81 — install via: brew install make, then use gmake)
endif
.SILENT:
.ONESHELL:
.PHONY: \
recipe_a recipe_b \
help
.DEFAULT_GOAL := help
# -- config --
VERBOSE ?= 0
ifeq ($(VERBOSE),0)
# quiet flags per tool
endif
Conventions
- snake_case for all recipe names
## descriptioncomment on every public recipe (for help output)# MARK: SECTIONto group related recipessetup_*prefix for installation recipes (never bareinstall)validatechainslint+test(when both exist)- Idempotent setup:
command -v X >/dev/null || install X - No hardcoded paths — use variables at top of file
VERBOSE ?= 0with conditional quiet flags per tool- Zero-sudo installs — use
~/.local/binor~/.local/share/<tool>, neversudo apt/dnf export PATH=...inside recipes that invoke tools installed to a non-default prefix (e.g. user-local npm)
Approach
- Detect what kind of project this is — look at build files, dependency manifests, and source file types in the working directory. If
$ARGUMENTSnames a type, use that instead. - Find a scaffold — list
references/scaffold-*.mdin this skill's directory. If one matches the detected project type, read it for language-specific recipe templates. If none matches, build recipes from first principles using the conventions above. - Merge the scaffold's recipes with the required structure (version guard, .SILENT, .ONESHELL, .PHONY, help, config variables). The scaffold provides the MARK sections and recipe bodies; the required structure wraps them.
- Check if a Makefile already exists — if yes, review it against conventions and the scaffold. If no, create one from the merged template.
- Lint with
references/lint-makefile.sh— fix any failures. - Verify
make helprenders all recipes,make validate(ormake lint) runs clean.
The scaffold files shipped with this skill are starting points, not an exhaustive list. For a project type without a matching scaffold, apply the same conventions and recipe structure — the patterns (setup, dev, help) are universal.
Help Recipe (include in every Makefile)
help: ## Show available recipes grouped by section
echo "Usage: make [recipe]"
echo ""
awk '/^# MARK:/ { \
section = substr($$0, index($$0, ":")+2); \
printf "\n\033[1m%s\033[0m\n", section \
} \
/^[a-zA-Z0-9_-]+:.*?##/ { \
helpMessage = match($$0, /## (.*)/); \
if (helpMessage) { \
recipe = $$1; \
sub(/:/, "", recipe); \
printf " \033[36m%-22s\033[0m %s\n", recipe, substr($$0, RSTART + 3, RLENGTH) \
} \
}' $(MAKEFILE_LIST)
Quality Gates
- GNU Make version guard present
-
.SILENT,.ONESHELL,.DEFAULT_GOAL := helpset - Full
.PHONYlist up front - Every recipe has
## descriptioncomment -
# MARK:sections group related recipes -
snake_caserecipe names only -
helprecipe with standard awk pattern -
VERBOSE ?= 0with quiet mode support - No
sudoin setup recipes (user-local installs only) -
lint-makefile.shpasses