home / skills / itechmeat / llm-code / makefile

makefile skill

/skills/makefile

npx playbooks add skill itechmeat/llm-code --skill makefile

Review the files below or copy the command above to add this skill to your agents.

Files (9)
SKILL.md
6.4 KB
---
name: makefile
description: GNU Make automation and build system guidance
version: 2.0.0
release_date: "2023-02-26"
---

# Makefile Skill

Guidance for creating and maintaining GNU Make build automation.

## Quick Navigation

| Topic                         | Reference                               |
| ----------------------------- | --------------------------------------- |
| Rules, prerequisites, targets | [syntax.md](references/syntax.md)       |
| Variable types and assignment | [variables.md](references/variables.md) |
| Built-in functions            | [functions.md](references/functions.md) |
| Special and phony targets     | [targets.md](references/targets.md)     |
| Recipe execution, parallel    | [recipes.md](references/recipes.md)     |
| Implicit and pattern rules    | [implicit.md](references/implicit.md)   |
| Common practical patterns     | [patterns.md](references/patterns.md)   |

---

## Core Concepts

### Rule Structure

```makefile
target: prerequisites
        recipe
```

**Critical:** Recipe lines MUST start with TAB character.

### File vs Phony Targets

```makefile
# File target - creates/updates a file
build/app.o: src/app.c
        $(CC) -c $< -o $@

# Phony target - action, not a file
.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  |

```makefile
CC := gcc              # Immediate
CFLAGS ?= -O2          # Default, overridable
DEBUG = $(VERBOSE)     # Late binding
CFLAGS += -Wall        # Append
```

### Automatic Variables

| Variable | Meaning                         |
| -------- | ------------------------------- |
| `$@`     | Target                          |
| `$<`     | First prerequisite              |
| `$^`     | All prerequisites (unique)      |
| `$?`     | Prerequisites newer than target |
| `$*`     | Stem in pattern rules           |

---

## Essential Patterns

### Self-Documenting Help

```makefile
.DEFAULT_GOAL := help

help: ## Show available targets
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "  %-15s %s\n", $$1, $$2}'

install: ## Install dependencies
	uv sync

test: ## Run tests
	uv run pytest
```

### Platform Detection

```makefile
UNAME_S := $(shell uname -s)

ifeq ($(UNAME_S),Darwin)
    OPEN := open
else ifeq ($(UNAME_S),Linux)
    OPEN := xdg-open
endif
```

### Build Directory

```makefile
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

```makefile
export PYTHONPATH := $(PWD)/src
export DATABASE_URL

test:
	pytest tests/  # sees exported variables
```

---

## Common Targets

### Quality Checks

```makefile
.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

```makefile
.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

```makefile
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

```makefile
# Won't work - cd lost between lines
bad:
	cd subdir
	pwd           # Still in original dir!

# Correct - combine commands
good:
	cd subdir && pwd

# Or use line continuation
also-good:
	cd subdir && \
	pwd && \
	make
```

### Silent and Error Handling

```makefile
target:
	@echo "@ suppresses command echo"
	-rm -f maybe.txt    # - ignores errors
```

### Parallel Execution

```bash
make -j4              # 4 parallel jobs
make -j4 lint test    # Run lint and test in parallel
```

---

## Output Discipline

**One line in, one line out.** Avoid echo spam.

```makefile
# ❌ Too chatty
start:
	@echo "Starting services..."
	docker compose up -d
	@echo "Waiting..."
	@sleep 3
	@echo "Done!"

# ✅ Concise
start: ## Start services
	@echo "Starting at http://localhost:8000 ..."
	@docker compose up -d
	@echo "Logs: docker compose logs -f"
```

---

## Conditionals

```makefile
DEBUG ?= 0

ifeq ($(DEBUG),1)
    CFLAGS += -g -O0
else
    CFLAGS += -O2
endif

ifdef CI
    TEST_FLAGS := --ci
endif
```

---

## Including Files

```makefile
# Required include (error if missing)
include config.mk

# Optional include (silent if missing)
-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

```makefile
# Makefile Template
.DEFAULT_GOAL := help
SHELL := /bin/bash
.SHELLFLAGS := -ec

.PHONY: help install test lint format clean

help: ## Show this help
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
		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
```

---

## See Also

- [GNU Make Manual](https://www.gnu.org/software/make/manual/make.html)
- [patterns.md](references/patterns.md) - Extended patterns and recipes