makefile

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Makefile Helper

Makefile 助手

Create Makefiles that are simple, discoverable, and maintainable.
创建简单、易发现、可维护的Makefile。

Core Principles

核心原则

  1. Default to rich help - Use categorized help with emoji headers unless user requests minimal
  2. Ask about structure upfront - For new Makefiles, ask: "Flat or modular? Rich help or minimal?"
  3. Follow existing conventions - Match the project's style if Makefile already exists
  4. Don't over-engineer - Solve the immediate need, not hypothetical futures
  5. Use
    uv run
    - Always run Python commands via
    uv run
    for venv context
  6. Explain decisions - If choosing flat/minimal, explain why before generating
  1. 默认提供丰富帮助 - 除非用户要求极简版本,否则使用带emoji标题的分类帮助
  2. 提前确认结构 - 对于新的Makefile,询问:「扁平结构还是模块化结构?丰富帮助还是极简帮助?」
  3. 遵循现有约定 - 如果项目已存在Makefile,匹配项目原有风格
  4. 不要过度设计 - 解决当前需求即可,无需考虑假设的未来场景
  5. 使用
    uv run
    - 始终通过
    uv run
    运行Python命令以继承虚拟环境上下文
  6. 解释决策逻辑 - 如果选择扁平/极简结构,生成前先说明原因

When to Use This Skill

适用场景

  • Creating a new Makefile for a project
  • Adding specific targets to an existing Makefile
  • Improving/refactoring an existing Makefile
  • Setting up CI/CD make targets
  • Distributing pre-built binaries via GitHub Releases
  • 为项目创建全新的Makefile
  • 向现有Makefile添加特定目标
  • 优化/重构现有Makefile
  • 设置CI/CD对应的make目标
  • 通过GitHub Releases分发预构建二进制文件

Quick Start

快速开始

For new projects, use the appropriate template:
Project TypeTemplateComplexity
Any project
templates/base.mk
Minimal
Python with uv
templates/python-uv.mk
Standard
Python FastAPI
templates/python-fastapi.mk
Full-featured
Node.js
templates/nodejs.mk
Standard
Go
templates/go.mk
Standard
Chrome Extension
templates/chrome-extension.mk
Modular
Flutter App
templates/flutter.mk
Modular
对于新项目,使用对应模板即可:
项目类型模板复杂度
任意项目
templates/base.mk
极简
使用uv的Python项目
templates/python-uv.mk
标准
Python FastAPI项目
templates/python-fastapi.mk
全功能
Node.js项目
templates/nodejs.mk
标准
Go项目
templates/go.mk
标准
Chrome 扩展
templates/chrome-extension.mk
模块化
Flutter 应用
templates/flutter.mk
模块化

Chrome Extension Structure

Chrome 扩展结构

The chrome extension template uses a modular structure:
Makefile                              # Main file with help + includes
makefiles/
  colors.mk                           # ANSI colors & print helpers
  common.mk                           # Shell flags, VERBOSE mode, guards
  build.mk                            # Build zip, version bump, releases
  dev.mk                              # Test, lint, clean, install
Copy from
templates/chrome-extension-modules/
to your project's
makefiles/
directory.
Key features:
  • build-release
    - Version bump menu (major/minor/patch) + zip for Chrome Web Store
  • build-beta
    - (Optional) GitHub releases with
    gh
    CLI
  • dev-test
    /
    dev-test-e2e
    - Vitest + Playwright testing
  • VERBOSE=1 make <target>
    - Show commands for debugging
Chrome扩展模板使用模块化结构:
Makefile                              # 主文件,包含帮助信息和引入声明
makefiles/
  colors.mk                           # ANSI颜色与打印辅助函数
  common.mk                           # Shell标志、VERBOSE模式、防护逻辑
  build.mk                            # 构建zip包、版本号升级、发布
  dev.mk                              # 测试、 lint、清理、安装
templates/chrome-extension-modules/
下的文件复制到项目的
makefiles/
目录即可。
核心功能:
  • build-release
    - 版本号升级菜单(主版本/次版本/修订版)+ 生成Chrome应用商店所需的zip包
  • build-beta
    - (可选)通过
    gh
    CLI发布到GitHub releases
  • dev-test
    /
    dev-test-e2e
    - Vitest + Playwright 测试
  • VERBOSE=1 make <target>
    - 显示执行的命令用于调试

Flutter App Structure

Flutter 应用结构

Makefile                    # Main file with help + includes
makefiles/
  colors.mk                # ANSI colors & print helpers
  common.mk                # Shell flags, VERBOSE mode, guards
  dev.mk                   # Setup, run simulator/device, devices, clean
  build.mk                 # iOS/Android builds (IPA, APK, AAB)
  deploy.mk                # TestFlight upload
  lint.mk                  # Dart analyze & format
Copy from
templates/flutter-modules/
to your project's
makefiles/
directory.
Key features:
  • flutter-run-ios
    auto-boots simulator and waits for it
  • flutter-run-android
    auto-launches emulator and waits for it
  • flutter-run-device
    auto-detects or uses
    FLUTTER_IOS_DEVICE
    /
    FLUTTER_ANDROID_DEVICE
  • flutter-build-ipa
    +
    flutter-deploy-testflight
    full iOS release workflow
  • flutter-lint FIX=true
    Dart formatting with FIX pattern
  • VERBOSE=1 make <target>
    show commands for debugging
Makefile                    # 主文件,包含帮助信息和引入声明
makefiles/
  colors.mk                # ANSI颜色与打印辅助函数
  common.mk                # Shell标志、VERBOSE模式、防护逻辑
  dev.mk                   # 环境配置、运行模拟器/真机、设备列表、清理
  build.mk                 # iOS/Android构建(IPA、APK、AAB)
  deploy.mk                # 上传到TestFlight
  lint.mk                  # Dart 静态分析与格式化
templates/flutter-modules/
下的文件复制到项目的
makefiles/
目录即可。
核心功能:
  • flutter-run-ios
    自动启动模拟器并等待就绪
  • flutter-run-android
    自动启动安卓模拟器并等待就绪
  • flutter-run-device
    自动检测设备,或使用
    FLUTTER_IOS_DEVICE
    /
    FLUTTER_ANDROID_DEVICE
    指定设备
  • flutter-build-ipa
    +
    flutter-deploy-testflight
    完整iOS发布工作流
  • flutter-lint FIX=true
    带修复功能的Dart格式化
  • VERBOSE=1 make <target>
    显示执行的命令用于调试

Interaction Pattern

交互模式

  1. Understand - What specific problem are we solving?
  2. Check existing - Is there already a Makefile? Read it first!
  3. Default to modular - For 5+ targets, use modular structure unless user requests flat
  4. Match preferences - Use python-fastapi.mk template style as default for rich help
  5. Explain structure - If you choose flat/minimal, explain the reasoning
  6. Iterate - Add complexity or simplify based on feedback
  1. 理解需求 - 明确我们要解决的具体问题是什么?
  2. 检查现有文件 - 是否已经存在Makefile?先阅读现有内容!
  3. 默认使用模块化 - 目标超过5个时,除非用户要求扁平结构,否则默认使用模块化结构
  4. 匹配用户偏好 - 默认使用python-fastapi.mk模板的丰富帮助风格
  5. 说明结构选择 - 如果选择扁平/极简结构,解释选择的原因
  6. 迭代优化 - 根据反馈增加复杂度或简化

Naming Conventions

命名规范

Use kebab-case with consistent prefix-based grouping:
makefile
undefined
使用kebab-case命名,通过前缀统一分组:
makefile
undefined

Good - consistent prefixes (hyphens, not underscores)

好的示例 - 前缀统一(使用连字符,不使用下划线)

build-release, build-zip, build-clean # Build tasks dev-run, dev-test, dev-lint # Development tasks db-start, db-stop, db-migrate # Database tasks env-local, env-prod, env-show # Environment tasks
build-release, build-zip, build-clean # 构建相关任务 dev-run, dev-test, dev-lint # 开发相关任务 db-start, db-stop, db-migrate # 数据库相关任务 env-local, env-prod, env-show # 环境相关任务

Internal targets - prefix with underscore to hide from help

内部目标 - 下划线前缀,不会出现在帮助中

_build-zip-internal, _prompt-version # Not shown in make help
_build-zip-internal, _prompt-version # 不会在make help中显示

Bad - inconsistent

不好的示例 - 不统一

run-dev, build, localEnv, test_net build_release, dev_test # Underscores - don't use

**Name targets after the action, not the tool:**
```makefile
run-dev, build, localEnv, test_net build_release, dev_test # 不要使用下划线

**目标按动作命名,不要按工具命名:**
```makefile

Good - describes what it does

好的示例 - 描述功能

remove-bg # Removes background from image format-code # Formats code lint-check # Runs linting
remove-bg # 移除图片背景 format-code # 格式化代码 lint-check # 执行lint检查

Bad - names the tool

不好的示例 - 只写工具名

rembg # What does this do? prettier # Is this running prettier or configuring it? eslint # Unclear
undefined
rembg # 不知道是做什么的? prettier # 是运行prettier还是配置prettier? eslint # 含义不明确
undefined

Key Patterns

核心模式

Binary Distribution

二进制分发

For projects distributed as pre-built binaries via GitHub Releases:
makefile
GITHUB_REPO ?= owner/repo
OS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
ARCH := $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')

.PHONY: install-cli
install-cli: ## Download and install CLI from latest GitHub release
	@RELEASE=$$(curl -fsSL https://api.github.com/repos/$(GITHUB_REPO)/releases/latest | grep tag_name | cut -d'"' -f4); \
	echo "Installing $$RELEASE for $(OS)/$(ARCH)..."; \
	curl -fsSL -o ~/.local/bin/cli \
		"https://github.com/$(GITHUB_REPO)/releases/download/$$RELEASE/cli-$(OS)-$(ARCH)"; \
	chmod +x ~/.local/bin/cli
Key considerations:
  • Detect OS and architecture automatically
  • Download from GitHub Releases (no Python/uv required)
  • Install to
    ~/.local/bin
    (user-writable, in PATH)
  • Preserve existing config files during updates
对于通过GitHub Releases分发预构建二进制文件的项目:
makefile
GITHUB_REPO ?= owner/repo
OS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
ARCH := $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')

.PHONY: install-cli
install-cli: ## 从最新GitHub release下载并安装CLI
	@RELEASE=$$(curl -fsSL https://api.github.com/repos/$(GITHUB_REPO)/releases/latest | grep tag_name | cut -d'"' -f4); \
	echo "正在为$(OS)/$(ARCH)安装$$RELEASE..."; \
	curl -fsSL -o ~/.local/bin/cli \
		"https://github.com/$(GITHUB_REPO)/releases/download/$$RELEASE/cli-$(OS)-$(ARCH)"; \
	chmod +x ~/.local/bin/cli
核心注意点:
  • 自动检测操作系统和架构
  • 从GitHub Releases下载(无需Python/uv)
  • 安装到
    ~/.local/bin
    (用户可写,默认在PATH中)
  • 更新时保留现有配置文件

Always Use
uv run
for Python

Python命令始终使用
uv run

makefile
undefined
makefile
undefined

Good - uses uv run with ruff (modern tooling)

好的示例 - 结合现代工具链使用uv run

dev-check: uv run ruff check src/ tests/ uv run ruff format --check src/ tests/ uv run mypy src/
dev-format: uv run ruff check --fix src/ tests/ uv run ruff format src/ tests/
dev-check: uv run ruff check src/ tests/ uv run ruff format --check src/ tests/ uv run mypy src/
dev-format: uv run ruff check --fix src/ tests/ uv run ruff format src/ tests/

Bad - relies on manual venv activation

不好的示例 - 依赖手动激活虚拟环境

dev-format: ruff format .
undefined
dev-format: ruff format .
undefined

Use
uv sync
(not pip install)

使用
uv sync
(不要用pip install)

makefile
env-install:
	uv sync  # Uses pyproject.toml + lock file
makefile
env-install:
	uv sync  # 使用pyproject.toml + lock文件

Categorized Help (for 5+ targets)

分类帮助(目标超过5个时使用)

makefile
help:
	@printf "$(BOLD)=== 🚀 API ===$(RESET)\n"
	@printf "$(CYAN)%-25s$(RESET) %s\n" "api-run" "Start server"
	@printf "%-25s $(GREEN)make api-run [--reload]$(RESET)\n" ""
Makefile ordering rule - help targets go LAST, just before catch-all:
  1. Configuration (
    ?=
    variables)
  2. HELP_PATTERNS
    definition
  3. Imports (
    include ./makefiles/*.mk
    )
  4. Main targets (grouped by function)
  5. help:
    and
    help-unclassified:
    targets
  6. Catch-all
    %:
    rule (absolute last)
makefile
help:
	@printf "$(BOLD)=== 🚀 API ===$(RESET)\n"
	@printf "$(CYAN)%-25s$(RESET) %s\n" "api-run" "启动服务"
	@printf "%-25s $(GREEN)make api-run [--reload]$(RESET)\n" ""
Makefile顺序规则 - 帮助目标放在最后,紧接在全局捕获规则之前:
  1. 配置(
    ?=
    定义的变量)
  2. HELP_PATTERNS
    定义
  3. 引入其他文件(
    include ./makefiles/*.mk
  4. 主目标(按功能分组)
  5. help:
    help-unclassified:
    目标
  6. 全局捕获
    %:
    规则(绝对放在最后)

Preflight Checks

前置检查

makefile
_check-docker:
	@docker info >/dev/null 2>&1 || { echo "Docker not running"; exit 1; }

db-start: _check-docker  # Runs check first
	docker compose up -d
makefile
_check-docker:
	@docker info >/dev/null 2>&1 || { echo "Docker未运行"; exit 1; }

db-start: _check-docker  # 先执行检查
	docker compose up -d

External Tool Dependencies

外部工具依赖

When a target requires an external tool (not a system service):
  • Don't create public install targets (no
    make install-foo
    )
  • Use internal check as dependency (prefix with
    _
    , no
    ##
    comment)
  • Show install command on failure - tell user what to run, don't do it for them
makefile
undefined
当目标需要外部工具(非系统服务)时:
  • 不要创建公开的安装目标(不要写
    make install-foo
  • 使用内部检查作为依赖(下划线前缀,不带
    ##
    注释)
  • 失败时显示安装命令 - 告诉用户需要执行什么命令,不要自动帮用户安装
makefile
undefined

Internal check - hidden from help (no ##)

内部检查 - 不在帮助中显示(无##)

_check-rembg: @command -v rembg >/dev/null 2>&1 || {
printf "$(RED)$(CROSS) rembg not installed$(RESET)\n";
printf "$(YELLOW)Run: uv tool install "rembg[cli]"$(RESET)\n";
exit 1;
}
_check-rembg: @command -v rembg >/dev/null 2>&1 || {
printf "$(RED)$(CROSS) 未安装rembg$(RESET)\n";
printf "$(YELLOW)执行:uv tool install "rembg[cli]"$(RESET)\n";
exit 1;
}

Public target - uses check as dependency

公开目标 - 依赖检查逻辑

.PHONY: remove-bg remove-bg: _check-rembg ## Remove background from image rembg i "$(IN)" "$(OUT)"

**Key points:**
- Name target after the action (`remove-bg`), not the tool (`rembg`)
- Check runs automatically - user just runs `make remove-bg`
- If tool missing, user sees exactly what command to run
.PHONY: remove-bg remove-bg: _check-rembg ## 移除图片背景 rembg i "$(IN)" "$(OUT)"

**核心要点:**
- 按动作命名目标(`remove-bg`),不要按工具命名(`rembg`)
- 检查自动执行 - 用户只需运行`make remove-bg`
- 如果工具未安装,用户可以直接看到需要执行的命令

Env File Loading

环境文件加载

Load
.env
and export to child processes:
makefile
undefined
加载
.env
文件并导出到子进程:
makefile
undefined

At top of Makefile, after .DEFAULT_GOAL

在Makefile顶部,.DEFAULT_GOAL之后

-include .env .EXPORT_ALL_VARIABLES:

For per-target env override:

```makefile
-include .env .EXPORT_ALL_VARIABLES:

按目标覆盖环境变量:

```makefile

Allow: E2E_ENV=.test.env make test-e2e

支持:E2E_ENV=.test.env make test-e2e

test-e2e: @set -a && . "$${E2E_ENV:-.env}" && set +a && uv run pytest tests/e2e/
undefined
test-e2e: @set -a && . "$${E2E_ENV:-.env}" && set +a && uv run pytest tests/e2e/
undefined

FIX Variable for Check/Format Targets

检查/格式化目标的FIX变量

Use a
FIX
variable to toggle between check-only and auto-fix modes:
makefile
FIX ?= false

dev-check: ## Run linting and type checks (FIX=false: check only)
	$(call print_section,Running checks)
ifeq ($(FIX),true)
	uv run ruff check --fix src/ tests/
	uv run ruff format src/ tests/
else
	uv run ruff check src/ tests/
	uv run ruff format --check src/ tests/
endif
	uv run mypy src/
	$(call print_success,All checks passed)
In help output, show usage:
makefile
@printf "$(CYAN)%-25s$(RESET) %s\n" "dev-check" "Run linting (FIX=false: check only)"
@printf "%-25s $(GREEN)make dev-check FIX=true$(RESET)  <- auto-fix issues\n" ""
使用
FIX
变量切换仅检查和自动修复模式:
makefile
FIX ?= false

dev-check: ## 执行lint和类型检查(FIX=false:仅检查)
	$(call print_section,执行检查)
ifeq ($(FIX),true)
	uv run ruff check --fix src/ tests/
	uv run ruff format src/ tests/
else
	uv run ruff check src/ tests/
	uv run ruff format --check src/ tests/
endif
	uv run mypy src/
	$(call print_success,所有检查通过)
在帮助输出中说明用法:
makefile
@printf "$(CYAN)%-25s$(RESET) %s\n" "dev-check" "执行lint检查(FIX=false:仅检查)"
@printf "%-25s $(GREEN)make dev-check FIX=true$(RESET)  <- 自动修复问题\n" ""

When to Modularize

什么时候使用模块化

Default to modular for any new Makefile with 5+ targets.
Use flat file only when:
  • Simple scripts or single-purpose tools
  • User explicitly requests it
  • < 5 targets with no expected growth
Standard modular structure:
Makefile              # Config, imports, help, catch-all
makefiles/
  colors.mk          # ANSI colors & print helpers
  common.mk          # Shell flags, VERBOSE, guards
  <domain>.mk        # Actual targets (build.mk, dev.mk, etc.)
目标超过5个的新Makefile默认使用模块化结构。
仅在以下情况使用扁平文件:
  • 简单脚本或单一用途工具
  • 用户明确要求
  • 目标少于5个且预期不会增加
标准模块化结构:
Makefile              # 配置、引入、帮助、全局捕获
makefiles/
  colors.mk          # ANSI颜色与打印辅助函数
  common.mk          # Shell标志、VERBOSE、防护逻辑
  <领域>.mk        # 实际目标(build.mk、dev.mk等)

Legacy Compatibility

遗留兼容

Default: NO legacy aliases. Only add when:
  • User explicitly requests backwards compatibility
  • Existing CI/scripts depend on old names (verify with
    rg "make old-name"
    )
When legacy IS needed, put them in a clearly marked section AFTER main targets but BEFORE help:
makefile
############################
默认不添加遗留别名。 仅在以下情况添加:
  • 用户明确要求向后兼容
  • 现有CI/脚本依赖旧名称(通过
    rg "make old-name"
    验证)
需要兼容遗留时,放在主目标之后、帮助目标之前的明确标记区域:
makefile
############################

Legacy Target Aliases

遗留目标别名

############################
.PHONY: old-name old-name: new_name ## (Legacy) Description
undefined
############################
.PHONY: old-name old-name: new_name ## (遗留)描述
undefined

Key Rules

核心规则

  • Always read existing Makefile before changes
  • Search codebase before renaming targets (
    rg "make old-target"
    )
  • Test with
    make help
    and
    make -n target
  • Update docs after Makefile changes - When adding new targets:
    1. Add to
      make help
      output (in the appropriate section)
    2. Update
      CLAUDE.md
      if the project has one (document new targets)
    3. Update any other relevant docs (README.md, Agents.md, etc.)
  • Never add targets without clear purpose
  • No line-specific references - Avoid patterns like "Makefile:44" in docs/comments; use target names instead
  • Single source of truth - Config vars defined once in root Makefile, not duplicated in modules
  • Help coverage audit - All targets with
    ##
    must appear in either
    make help
    or
    make help-unclassified
  • 修改前始终先阅读现有Makefile
  • 重命名目标前搜索代码库
    rg "make old-target"
  • 使用
    make help
    make -n target
    测试
  • Makefile修改后更新文档 - 新增目标时:
    1. 添加到
      make help
      输出的对应分类中
    2. 如果项目有
      CLAUDE.md
      ,更新该文件记录新目标
    3. 更新其他相关文档(README.md、Agents.md等)
  • 不要添加无明确用途的目标
  • 不要引用行号 - 避免在文档/注释中使用类似「Makefile:44」的模式,改用目标名称
  • 单一数据源 - 配置变量在根Makefile中定义一次,不要在模块中重复定义
  • 帮助覆盖度审计 - 所有带
    ##
    的目标必须出现在
    make help
    make help-unclassified

Help System

帮助系统

ASCII box title for visibility:
makefile
help:
	@printf "\n"
	@printf "$(BOLD)$(CYAN)╔═══════════════════════════╗$(RESET)\n"
	@printf "$(BOLD)$(CYAN)║     Project Name          ║$(RESET)\n"
	@printf "$(BOLD)$(CYAN)╚═══════════════════════════╝$(RESET)\n\n"
Categorized help with sections:
makefile
	@printf "$(BOLD)=== 🏗️  Build ===$(RESET)\n"
	@grep -h -E '^build-[a-zA-Z_-]+:.*?## .*$$' ... | awk ...
	@printf "$(BOLD)=== 🔧 Development ===$(RESET)\n"
	@grep -h -E '^dev-[a-zA-Z_-]+:.*?## .*$$' ... | awk ...
Key help patterns:
  • help
    - Main categorized help
  • help-unclassified
    - Show targets not in any category (useful for auditing)
  • help-all
    - Show everything including internal targets
  • Hidden targets: prefix with
    _
    (e.g.,
    _build-internal
    )
  • Legacy targets: label with
    ## (Legacy)
    and filter from main help
Always include a Help section in
make help
output:
makefile
	@printf "$(BOLD)=== ❓ Help ===$(RESET)\n"
	@printf "$(CYAN)%-25s$(RESET) %s\n" "help" "Show this help"
	@printf "$(CYAN)%-25s$(RESET) %s\n" "help-unclassified" "Show targets not in categorized help"
	@printf "\n"
help-unclassified pattern (note the
sed
to strip filename prefix):
makefile
help-unclassified: ## Show targets not in categorized help
	@printf "$(BOLD)Targets not in main help:$(RESET)\n"
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
		sed 's/^[^:]*://' | \
		grep -v -E '^(env-|dev-|clean|help)' | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-25s$(RESET) %s\n", $$1, $$2}' || \
		printf "  (none)\n"
Description format - one line with example:
makefile
undefined
使用ASCII框标题提高可见性:
makefile
help:
	@printf "\n"
	@printf "$(BOLD)$(CYAN)╔═══════════════════════════╗$(RESET)\n"
	@printf "$(BOLD)$(CYAN)║     项目名称          ║$(RESET)\n"
	@printf "$(BOLD)$(CYAN)╚═══════════════════════════╝$(RESET)\n\n"
分分类的帮助内容:
makefile
	@printf "$(BOLD)=== 🏗️  构建 ===$(RESET)\n"
	@grep -h -E '^build-[a-zA-Z_-]+:.*?## .*$$' ... | awk ...
	@printf "$(BOLD)=== 🔧 开发 ===$(RESET)\n"
	@grep -h -E '^dev-[a-zA-Z_-]+:.*?## .*$$' ... | awk ...
核心帮助模式:
  • help
    - 主分类帮助
  • help-unclassified
    - 显示未归入任何分类的目标(用于审计)
  • help-all
    - 显示所有内容包括内部目标
  • 隐藏目标:下划线前缀(例如
    _build-internal
  • 遗留目标:标记
    ## (Legacy)
    并从主帮助中过滤
make help
输出必须包含帮助分类:
makefile
	@printf "$(BOLD)=== ❓ 帮助 ===$(RESET)\n"
	@printf "$(CYAN)%-25s$(RESET) %s\n" "help" "显示此帮助"
	@printf "$(CYAN)%-25s$(RESET) %s\n" "help-unclassified" "显示未归入分类的目标"
	@printf "\n"
help-unclassified模式(注意用
sed
去除文件名前缀):
makefile
help-unclassified: ## 显示未归入分类的目标
	@printf "$(BOLD)未出现在主帮助中的目标:$(RESET)\n"
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
		sed 's/^[^:]*://' | \
		grep -v -E '^(env-|dev-|clean|help)' | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-25s$(RESET) %s\n", $$1, $$2}' || \
		printf "  (无)\n"
描述格式 - 一行描述加示例:
makefile
undefined

Good - concise description + example on next line

好的示例 - 简洁描述 + 下一行示例

@printf "$(CYAN)%-14s$(RESET) %s\n" "scrape" "Fetch posts into SQLite, detect problems" @printf " $(GREEN)make scrape SUBREDDITS=python,django LIMIT=10$(RESET)\n" @printf "$(CYAN)%-14s$(RESET) %s\n" "dev-check" "Run ruff linter and formatter" @printf " $(GREEN)make dev-check FIX=true$(RESET)\n"
@printf "$(CYAN)%-14s$(RESET) %s\n" "scrape" "拉取帖子存入SQLite,检测问题" @printf " $(GREEN)make scrape SUBREDDITS=python,django LIMIT=10$(RESET)\n" @printf "$(CYAN)%-14s$(RESET) %s\n" "dev-check" "运行ruff linter和格式化工具" @printf " $(GREEN)make dev-check FIX=true$(RESET)\n"

Bad - too verbose, multi-line explanation

不好的示例 - 太冗长,多行解释

@printf " $(CYAN)$(BOLD)setup$(RESET)\n" @printf " Install Python dependencies using uv. Run this once after cloning.\n" @printf " Creates .venv/ and installs packages from pyproject.toml.\n" @printf " $(GREEN)make setup$(RESET)\n"

**Help description rules:**
- **One line max** - Description must fit on single line unless user explicitly asks for more
- **Include what it affects** - e.g., "creates .venv", "exports to CSV", "deletes database"
- **Example on next line** - Show realistic usage with parameters in `$(GREEN)`
- **Skip examples for simple targets** - If no parameters, no example needed

**Catch-all redirects to help:**
```makefile
%:
	@printf "$(RED)Unknown target '$@'$(RESET)\n"
	@$(MAKE) help
@printf " $(CYAN)$(BOLD)setup$(RESET)\n" @printf " 使用uv安装Python依赖,克隆项目后运行一次即可。\n" @printf " 创建.venv/目录并从pyproject.toml安装包。\n" @printf " $(GREEN)make setup$(RESET)\n"

**帮助描述规则:**
- **最多一行** - 除非用户明确要求更多内容,否则描述必须在一行内显示
- **说明影响范围** - 例如「创建.venv」、「导出为CSV」、「删除数据库」
- **示例放在下一行** - 用`$(GREEN)`显示带参数的真实用法
- **简单目标跳过示例** - 没有参数的目标不需要示例

**全局捕获规则重定向到帮助:**
```makefile
%:
	@printf "$(RED)未知目标'$@'$(RESET)\n"
	@$(MAKE) help

Common Pitfalls

常见陷阱

IssueFix
$var
in shell loops
Use
$$var
to escape for make
Catch-all
%:
shows error
Redirect to
@$(MAKE) help
instead
Config vars scatteredPut all
?=
overridable defaults at TOP of root Makefile
HELP_PATTERNS
mismatch
Must match grep patterns in help target exactly
Duplicate defs in modulesDefine once in root, reference in modules
Trailing whitespace in varsCauses path splitting bugs - trim all variable definitions
.PHONY
on file targets
Only use
.PHONY
for non-file targets
Too many public targetsDon't expose
install-X
or
check-X
- use internal
_check-X
dependencies
$(DIM)
for usage text
Appears grey/unreadable - use
$(GREEN)
instead
Target named after toolName after the action:
remove-bg
not
rembg
help-unclassified
shows filename
Use
sed 's/^[^:]*://'
to strip
Makefile:
prefix
No
.env
export
Add
-include .env
and
.EXPORT_ALL_VARIABLES:
at top
问题修复方案
Shell循环中的
$var
使用
$$var
转义供make解析
全局捕获
%:
显示错误
改为重定向到
@$(MAKE) help
配置变量分散将所有
?=
可覆盖默认值放在根Makefile顶部
HELP_PATTERNS
不匹配
必须与帮助目标中的grep模式完全一致
模块中重复定义在根目录定义一次,模块中引用
变量末尾空格会导致路径拆分错误,修剪所有变量定义的末尾空格
文件目标加
.PHONY
仅对非文件目标使用
.PHONY
公开目标太多不要暴露
install-X
check-X
,使用内部
_check-X
依赖
用法文本用
$(DIM)
会显示为灰色/不可读,改用
$(GREEN)
目标按工具命名按动作命名:
remove-bg
而不是
rembg
help-unclassified
显示文件名
使用
sed 's/^[^:]*://'
去除
Makefile:
前缀
未导出
.env
在顶部添加
-include .env
.EXPORT_ALL_VARIABLES:

Cleanup Makefile Workflow

Makefile清理工作流

When user says "cleanup my makefiles":
IMPORTANT: Build a plan first and explain it to the user before implementing anything.
当用户说「清理我的makefile」时:
重要:先制定计划并向用户解释,确认后再执行任何修改。

Phase 1: Audit (no changes yet)

阶段1:审计(暂不修改)

bash
make help                    # See categorized targets
make help-unclassified       # Find orphaned targets
cat Makefile                 # Read structure
ls makefiles/*.mk 2>/dev/null # Check if modular
rg "make " --type md         # Find external dependencies
grep -E '\s+$' Makefile makefiles/*.mk  # Trailing whitespace
bash
make help                    # 查看分类目标
make help-unclassified       # 查找孤立目标
cat Makefile                 # 阅读结构
ls makefiles/*.mk 2>/dev/null # 检查是否模块化
rg "make " --type md         # 查找外部依赖
grep -E '\s+$' Makefile makefiles/*.mk  # 末尾空格

Phase 2: Build & Present Plan

阶段2:制定并展示计划

Create a checklist of proposed changes:
  • Structure - Convert flat → modular (if 5+ targets) or vice versa
  • Legacy removal - List specific targets to delete (with dependency check)
  • Duplicates - List targets to consolidate
  • Renames - List
    old_name
    new-name
    changes
  • Description rewrites - List vague descriptions to improve
  • Missing targets - Suggest targets that should exist (e.g.,
    help-unclassified
    )
  • Ordering fixes - Config → imports → targets → help → catch-all
Ask user to approve the plan before proceeding.
创建建议修改的检查清单:
  • 结构 - 扁平转模块化(如果目标超过5个)或相反
  • 遗留移除 - 列出要删除的具体目标(已做依赖检查)
  • 重复项 - 列出要合并的目标
  • 重命名 - 列出
    old_name
    new-name
    的修改项
  • 描述重写 - 列出要优化的模糊描述
  • 缺失目标 - 建议应该添加的目标(例如
    help-unclassified
  • 顺序修复 - 配置 → 引入 → 目标 → 帮助 → 全局捕获
继续前请先获得用户对计划的批准。

Phase 3: Implement (after approval)

阶段3:执行(批准后)

  1. Restructure (if needed) - Create
    makefiles/
    directory, split into modules
  2. Remove legacy - Delete approved targets
  3. Consolidate duplicates - Merge into single targets
  4. Rename targets - Apply hyphen convention, add
    _
    prefix for internal
  5. Rewrite descriptions - Make each
    ##
    explain the purpose
  6. Fix formatting
    • Usage examples in yellow:
      $(YELLOW)make foo$(RESET)
    • Remove trailing whitespace
    • .PHONY
      only on non-file targets
  7. Add missing pieces -
    help-unclassified
    , catch-all
    %:
    , etc.
  1. 结构调整(如果需要) - 创建
    makefiles/
    目录,拆分到模块
  2. 移除遗留 - 删除已批准的目标
  3. 合并重复项 - 合并为单一目标
  4. 重命名目标 - 应用连字符规范,内部目标加
    _
    前缀
  5. 重写描述 - 每个
    ##
    都要清晰说明用途
  6. 修复格式
    • 用法示例用黄色:
      $(YELLOW)make foo$(RESET)
    • 移除末尾空格
    • 仅非文件目标加
      .PHONY
  7. 添加缺失部分 -
    help-unclassified
    、全局捕获
    %:

Phase 4: Verify

阶段4:验证

bash
make help          # Clean output?
make help-unclassified  # Should be empty or minimal
make -n <target>   # Dry-run key targets
bash
make help          # 输出是否清晰?
make help-unclassified  # 应该为空或极少内容
make -n <target>   # 核心目标试运行

What NOT to do without asking:

未询问用户前不要做的操作:

  • Rename targets that CI/scripts depend on
  • Remove targets that look unused
  • Change structure (flat ↔ modular) without approval
  • 重命名CI/脚本依赖的目标
  • 删除看起来未使用的目标
  • 未经批准修改结构(扁平 ↔ 模块化)

Files in This Skill

本技能包含的文件

  • reference.md
    - Detailed patterns, categorized help, error handling
  • templates/
    - Full copy-paste Makefiles for each stack
  • modules/
    - Reusable pieces for complex projects
  • reference.md
    - 详细模式、分类帮助、错误处理
  • templates/
    - 各技术栈可直接复制使用的完整Makefile
  • modules/
    - 复杂项目可复用的模块

Example: Adding a Target

示例:添加目标

User: "Add a target to run my tests"
makefile
.PHONY: test
test: ## Run tests
	$(call print_section,Running tests)
	uv run pytest tests/ -v
	$(call print_success,Tests passed)
User: "Add database targets"
makefile
.PHONY: db-start db-stop db-migrate

db-start: _check-docker ## Start database
	docker compose up -d postgres

db-stop: ## Stop database
	docker compose down

db-migrate: _check-postgres ## Run migrations
	uv run alembic upgrade head
用户:「添加一个运行测试的目标」
makefile
.PHONY: test
test: ## 运行测试
	$(call print_section,运行测试)
	uv run pytest tests/ -v
	$(call print_success,测试通过)
用户:「添加数据库相关目标」
makefile
.PHONY: db-start db-stop db-migrate

db-start: _check-docker ## 启动数据库
	docker compose up -d postgres

db-stop: ## 停止数据库
	docker compose down

db-migrate: _check-postgres ## 执行迁移
	uv run alembic upgrade head