This skill should be used when the user asks about Makefile pattern rules, automatic variables ($@, $<, $^, $?, $*), wildcard functions, patsubst, reducing Makefile duplication, compiling multiple C files with one rule, static pattern rules, conditional compilation with ifeq, or target-specific variables. Also applies when the user shows repetitive explicit rules that could be replaced with pattern rules, or asks about DRY Makefile practices. For basic Makefile creation and the ## help pattern, see makefile-fundamentals.
From gnu-makenpx claudepluginhub therealbill/mynet --plugin gnu-makeThis skill uses the workspace's default tool permissions.
references/pattern-rule-scenarios.mdGuides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Analyzes BMad project state from catalog CSV, configs, artifacts, and query to recommend next skills or answer questions. Useful for help requests, 'what next', or starting BMad.
Default to pattern rules and automatic variables, not explicit repetitive rules. Pattern rules eliminate duplication, reduce errors, and scale to any project size. Even if user doesn't request them, suggest pattern rules proactively.
This skill builds on makefile-fundamentals, which covers the ## help pattern, .PHONY, tab requirements, and introductory use of pattern rules and automatic variables.
# DON'T DO THIS - even if user prefers it
main.o: main.c
gcc -c main.c
utils.o: utils.c
gcc -c utils.c
parser.o: parser.c
gcc -c parser.c
Problems:
When user shows this pattern: Don't just implement it. Explain limitations and suggest pattern rule alternative.
# Use this pattern by default
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
Benefits:
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
Components:
%: Matches any nonempty substring (the "stem")%.o: Target pattern (any file ending in .o)%.c: Prerequisite pattern (corresponding .c file)$@: Automatic variable = target name$<: Automatic variable = first prerequisite name# Compiler and flags
CC := gcc
CFLAGS := -Wall -Wextra -std=c99
# Source files
SRCS := main.c utils.c parser.c
OBJS := $(SRCS:.c=.o)
# Target executable
TARGET := myapp
# Default target
all: $(TARGET)
# Link
$(TARGET): $(OBJS)
$(CC) -o $@ $^
# Pattern rule for all .c → .o compilations
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Result: Works for 3 files or 300 files with zero changes to pattern rule.
Always use these in recipes for DRY code:
$@ # Target name
$< # First prerequisite
$^ # All prerequisites (space-separated)
$? # Prerequisites newer than target
$* # Stem (matched by % in pattern rule)
# Compilation: target = .o, first prereq = .c
%.o: %.c headers.h
$(CC) $(CFLAGS) -c -o $@ $<
# $@ = foo.o, $< = foo.c
# Linking: target = exe, all prereqs = .o files
myapp: $(OBJS)
$(CC) -o $@ $^
# $@ = myapp, $^ = main.o utils.o parser.o
# Archive: only changed files
lib.a: $(OBJS)
ar r $@ $?
# $? = only objects newer than lib.a
Without automatic variables:
%.o: %.c
gcc -c -o %.o %.c # WRONG - % doesn't work here!
With automatic variables:
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $< # CORRECT
Automatic variables provide the actual matched names at execution time.
# Find all .c files in current directory
SRCS := $(wildcard *.c)
# Find all .c files recursively
SRCS := $(wildcard *.c src/*.c lib/*.c)
Use when: You want Makefile to adapt to new/removed files automatically.
# Convert .c list to .o list
OBJS := $(patsubst %.c,%.o,$(SRCS))
# Or shorter syntax:
OBJS := $(SRCS:.c=.o)
# Generate multiple targets
APPS := app1 app2 app3
all: $(APPS)
$(foreach app,$(APPS),$(eval $(app): $(app).c))
When user prefers explicit rules, acknowledge their perspective, then explain the scalability and maintenance limitations (N files = N rules to edit for any flag change). Show both approaches side-by-side with the pattern rule version as the recommended default.
Pattern rules are simpler — less code, fewer places to edit, impossible to have copy-paste inconsistencies. When user equates "simple" with "explicit rules for each file," reframe: more lines of identical code is more complexity, not less. Show a concrete line-count comparison.
For detailed scenarios covering C compilation, direct-to-executable builds, multiple extensions, auto-discovery with wildcard, and static pattern rules, see references/pattern-rule-scenarios.md.
DEBUG ?= 0
ifeq ($(DEBUG),1)
CFLAGS += -g -O0 -DDEBUG
else
CFLAGS += -O2 -DNDEBUG
endif
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
Usage:
make # Release mode
make DEBUG=1 # Debug mode
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
# Special flags for specific files
parser.o: CFLAGS += -Wno-unused-function
| Mistake | Fix | Why |
|---|---|---|
| Explicit rules for similar targets | Use pattern rule | DRY, scales better |
| Hardcoded filenames in recipes | Use automatic variables ($@, $<) | Reusable, error-free |
| Not using wildcard for file lists | Use $(wildcard *.c) | Adapts to new files |
| Repeating substitution patterns | Use patsubst or $(VAR:.c=.o) | Cleaner, maintainable |
| Writing make instead of $(MAKE) | Always use $(MAKE) | Flags pass through |
When creating Makefiles:
When reviewing Makefiles:
When user shows explicit rules:
When facing time pressure:
When reviewing any Makefile:
If any red flags present: Explain pattern rule benefits, even if user didn't ask for it.
Pattern rules and automatic variables are not "advanced features" - they're essential best practices.
Don't default to explicit rules because they seem "simpler" or the user is "in a hurry". Pattern rules:
Always suggest pattern rules first. Show explicit rules only as a "what not to do" comparison.
# C compilation
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
# C to executable
%: %.c
$(CC) $(CFLAGS) -o $@ $<
# Auto-discovery
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
# Linking
$(TARGET): $(OBJS)
$(CC) -o $@ $^
$@ # Target file name
$< # First prerequisite
$^ # All prerequisites
$? # Changed prerequisites
$* # Pattern stem