This skill should be used when the user asks about multi-directory Makefile builds, recursive make, building subdirectories, using make -C, structuring a project with multiple Makefiles, fixing make -j parallelism issues, replacing shell loops with phony targets, exporting variables to sub-makes, or using the $(MAKE) variable. Also applies when the user shows a for-loop pattern in a root Makefile for building subdirectories.
From gnu-makenpx claudepluginhub therealbill/mynet --plugin gnu-makeThis skill uses the workspace's default tool permissions.
Guides 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.
Multi-directory projects require coordination between root and subdirectory Makefiles. Use phony target pattern, not shell loops. Loop pattern prevents parallelization and breaks make -k. Even if user shows loop pattern, explain limitations and suggest proper structure.
# DON'T DO THIS - even if user requests it
SUBDIRS = lib app tests
all:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
Problems:
-j4 flag ignored, builds serialize-k flag broken: Continue-on-error doesn't work properly|| exit 1 for error propagationWhen user shows this pattern: Don't just accept it. Explain limitations and suggest proper alternative.
SUBDIRS = lib app tests
.PHONY: subdirs $(SUBDIRS)
# Main target depends on all subdirectories
subdirs: $(SUBDIRS)
# Each subdirectory is its own target
$(SUBDIRS):
$(MAKE) -C $@
Benefits:
make -j4 subdirs builds subdirs in parallel-k flag works: Continues building other subdirs after failure|| exit 1 neededSUBDIRS = lib app tests
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
# Declare dependencies
app tests: lib # app and tests both need lib built first
$(SUBDIRS):
$(MAKE) -C $@
Result: lib builds first, then app and tests build in parallel (with -j2+).
When the user prefers shell loops, acknowledge the approach, then explain the three concrete limitations: no parallelization with -j, broken -k continue-on-error behavior, and need for manual || exit 1 error handling. Show the phony target equivalent and note that make -j4 with phony targets can deliver 4-8x speedup on multi-directory projects.
| Approach | Parallelizes with -j? | -k flag works? | Complexity |
|---|---|---|---|
| Shell loop | ❌ No | ❌ No | High (needs |
| Phony targets | ✅ Yes | ✅ Yes | Low (clean) |
Always suggest phony target pattern, even if user shows loop preference.
Option 1: Export directive (recommended for few variables)
VERSION = 1.2.3
CFLAGS = -O2
export VERSION CFLAGS
subdirs: $(SUBDIRS)
# Variables automatically available in sub-makes
Option 2: Command-line passing
$(SUBDIRS):
$(MAKE) -C $@ VERSION=$(VERSION) CFLAGS="$(CFLAGS)"
Option 3: Export all (use sparingly)
export # Exports all variables
# Or use special target
.EXPORT_ALL_VARIABLES:
export VERSION
unexport TEMP_VAR # Don't pass this down
Always use $(MAKE) for recursive invocations, not hardcoded make:
# ✅ CORRECT
$(SUBDIRS):
$(MAKE) -C $@
# ❌ WRONG
$(SUBDIRS):
make -C $@
Why: $(MAKE) ensures -t, -n, and -q flags work correctly in recursive contexts.
SUBDIRS = frontend backend database
.PHONY: all clean $(SUBDIRS)
all: $(SUBDIRS)
clean:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir clean; \
done
$(SUBDIRS):
$(MAKE) -C $@
Note: Clean often uses loop (no parallelism needed), build uses phony pattern (parallelism desired).
SUBDIRS = core utils app tests docs
.PHONY: all $(SUBDIRS)
all: $(SUBDIRS)
# Dependency chain
utils: core
app: core utils
tests: core utils app
docs: app
$(SUBDIRS):
$(MAKE) -C $@
Result: Maximum parallelism while respecting build order.
BINARIES = cmd/server cmd/cli cmd/worker
.PHONY: build $(BINARIES)
build: $(BINARIES)
$(BINARIES):
go build -o bin/$(notdir $@) ./$@
clean:
rm -rf bin/
Note: Even without subdirectory Makefiles, phony pattern enables parallelism.
$(SUBDIRS):
$(MAKE) -C $@
# Errors stop build automatically
# No special handling needed
make -k subdirs # Builds all subdirs even if some fail
Works correctly with phony pattern, doesn't work properly with loops.
| Mistake | Fix | Why |
|---|---|---|
| Using loop for builds | Use phony target pattern | Enables parallelization |
Using make instead of $(MAKE) | Always use $(MAKE) | Flags pass through correctly |
| Not declaring subdirs as .PHONY | Add to .PHONY | Prevents conflicts |
| Forgetting dependencies | Add prerequisite lines | Controls build order |
| Using loop when phony works | Only loop for targets like clean | Phony enables -j flag |
When creating multi-directory builds:
When user shows loop pattern:
When debugging "make -j doesn't work":
make instead of $(MAKE)?.PHONY?If any red flags present: Explain phony target pattern as proper solution, even if user didn't ask for it.
Example: Project with 8 subdirectories, each taking 30 seconds to build.
Loop pattern:
make all # Takes 4 minutes (8 × 30s, serial)
Phony pattern:
make -j8 all # Takes ~30 seconds (parallel)
8x speedup by using correct pattern. Mention this when explaining to users.
Shell loops prevent parallelization. Even if user requests loops, explain the limitation and suggest phony target pattern. The performance difference matters for any non-trivial project, and the pattern is cleaner anyway.
Don't accept loop patterns without explanation - that's leaving 8x performance on the table.