makefile
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMakefile Skill
Makefile 技能指南
Guidance for creating and maintaining GNU Make build automation.
本文为创建和维护GNU Make构建自动化提供指导。
Quick Navigation
快速导航
| Topic | Reference |
|---|---|
| Rules, prerequisites, targets | syntax.md |
| Variable types and assignment | variables.md |
| Built-in functions | functions.md |
| Special and phony targets | targets.md |
| Recipe execution, parallel | recipes.md |
| Implicit and pattern rules | implicit.md |
| Common practical patterns | patterns.md |
| 主题 | 参考文档 |
|---|---|
| 规则、依赖项、目标 | syntax.md |
| 变量类型与赋值 | variables.md |
| 内置函数 | functions.md |
| 特殊与伪目标 | targets.md |
| 脚本执行、并行构建 | recipes.md |
| 隐式与模式规则 | implicit.md |
| 常见实用模式 | patterns.md |
Core Concepts
核心概念
Rule Structure
规则结构
makefile
target: prerequisites
recipeCritical: Recipe lines MUST start with TAB character.
makefile
target: prerequisites
recipe重要提示: 脚本行必须以TAB字符开头。
File vs Phony Targets
文件目标与伪目标
makefile
undefinedmakefile
undefinedFile target - creates/updates a file
文件目标 - 创建/更新文件
build/app.o: src/app.c
$(CC) -c $< -o $@
build/app.o: src/app.c
$(CC) -c $< -o $@
Phony target - action, not a file
伪目标 - 执行操作,而非生成文件
.PHONY: clean test install
clean:
rm -rf build/
undefined.PHONY: clean test install
clean:
rm -rf build/
undefinedVariable 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| 运算符 | 名称 | 展开时机 |
|---|---|---|
| 简单赋值 | 定义时一次性展开 |
| 条件赋值 | 仅当变量未设置时赋值 |
| 递归赋值 | 每次使用时展开(延迟绑定) |
| 追加赋值 | 向现有值添加内容 |
makefile
CC := gcc # 立即展开
CFLAGS ?= -O2 # 默认值,可被覆盖
DEBUG = $(VERBOSE) # 延迟绑定
CFLAGS += -Wall # 追加内容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 pytestmakefile
.DEFAULT_GOAL := help
help: ## 显示可用目标
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}'
install: ## 安装依赖
uv sync
test: ## 运行测试
uv run pytestPlatform Detection
平台检测
makefile
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
OPEN := open
else ifeq ($(UNAME_S),Linux)
OPEN := xdg-open
endifmakefile
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
OPEN := open
else ifeq ($(UNAME_S),Linux)
OPEN := xdg-open
endifBuild 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 $@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 variablesmakefile
export PYTHONPATH := $(PWD)/src
export DATABASE_URL
test:
pytest tests/ # 子进程可访问导出的变量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 checksmakefile
.PHONY: lint format check test
lint: ## 运行代码检查
ruff check .
mypy src/
format: ## 格式化代码
ruff format .
check: format lint test ## 执行所有质量检查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_cachemakefile
.PHONY: clean clean-all
clean: ## 移除构建产物
rm -rf build/ dist/ *.egg-info
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
clean-all: clean ## 移除所有生成文件
rm -rf .venv .pytest_cache .mypy_cacheDocker Integration
Docker集成
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)makefile
IMAGE := myapp
VERSION := $(shell git describe --tags --always)
docker-build: ## 构建Docker镜像
docker build -t $(IMAGE):$(VERSION) .
docker-run: ## 运行容器
docker run -d -p 8000:8000 $(IMAGE):$(VERSION)Recipe Execution
脚本执行
Each Line = Separate Shell
每行对应独立Shell
makefile
undefinedmakefile
undefinedWon't work - cd lost between lines
无效 - cd的效果在换行后丢失
bad:
cd subdir
pwd # Still in original dir!
bad:
cd subdir
pwd # 仍在原目录!
Correct - combine commands
正确 - 合并命令
good:
cd subdir && pwd
good:
cd subdir && pwd
Or use line continuation
或使用行继续符
also-good:
cd subdir &&
pwd &&
make
pwd &&
make
undefinedalso-good:
cd subdir &&
pwd &&
make
pwd &&
make
undefinedSilent and Error Handling
静默执行与错误处理
makefile
target:
@echo "@ suppresses command echo"
-rm -f maybe.txt # - ignores errorsmakefile
target:
@echo "@ 用于抑制命令回显"
-rm -f maybe.txt # - 用于忽略错误Parallel Execution
并行执行
bash
make -j4 # 4 parallel jobs
make -j4 lint test # Run lint and test in parallelbash
make -j4 # 4个并行任务
make -j4 lint test # 并行运行lint和testOutput Discipline
输出规范
One line in, one line out. Avoid echo spam.
makefile
undefined输入一行,输出一行。 避免过多冗余输出。
makefile
undefined❌ Too chatty
❌ 过于冗长
start:
@echo "Starting services..."
docker compose up -d
@echo "Waiting..."
@sleep 3
@echo "Done!"
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"
---start: ## 启动服务
@echo "服务启动地址:http://localhost:8000 ..."
@docker compose up -d
@echo "查看日志:docker compose logs -f"
---Conditionals
条件判断
makefile
DEBUG ?= 0
ifeq ($(DEBUG),1)
CFLAGS += -g -O0
else
CFLAGS += -O2
endif
ifdef CI
TEST_FLAGS := --ci
endifmakefile
DEBUG ?= 0
ifeq ($(DEBUG),1)
CFLAGS += -g -O0
else
CFLAGS += -O2
endif
ifdef CI
TEST_FLAGS := --ci
endifIncluding Files
文件包含
makefile
undefinedmakefile
undefinedRequired include (error if missing)
必需包含(文件缺失时报错)
include config.mk
include config.mk
Optional include (silent if missing)
可选包含(文件缺失时无提示)
-include local.mk
-include .env
----include local.mk
-include .env
---Common Pitfalls
常见陷阱
| Pitfall | Problem | Solution |
|---|---|---|
| Spaces in recipes | Recipes need TAB | Use actual TAB character |
| Missing .PHONY | | Declare |
| cd in recipes | Each line is new shell | Use |
| Unexpected late expansion | Use |
| Unexported vars | Subprocesses don't see vars | |
| Complex shell in make | Hard to maintain | Move to external script |
| 陷阱 | 问题 | 解决方案 |
|---|---|---|
| 脚本中使用空格 | 脚本行需要使用TAB字符 | 使用真实的TAB字符 |
| 缺少.PHONY | 若存在 | 声明 |
| 脚本中的cd命令 | 每行对应新的Shell | 使用 |
| 意外的延迟展开 | 默认使用 |
| 未导出变量 | 子进程无法访问变量 | |
| Make中嵌入复杂Shell脚本 | 难以维护 | 移至外部脚本 |
Quick Reference
快速参考
makefile
undefinedmakefile
undefinedMakefile Template
Makefile 模板
.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}'
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
---.DEFAULT_GOAL := help
SHELL := /bin/bash
.SHELLFLAGS := -ec
.PHONY: help install test lint format clean
help: ## 显示本帮助信息
@grep -E '^[a-zA-Z_-]+:.?## .$$' $(MAKEFILE_LIST) |
awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}'
awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}'
install: ## 安装依赖
uv sync --extra dev
test: ## 运行测试
uv run pytest tests/ -v
lint: ## 运行代码检查
uv run ruff check .
format: ## 格式化代码
uv run ruff format .
clean: ## 清理构建产物
rm -rf build/ dist/ .pytest_cache
---See Also
扩展阅读
- GNU Make Manual
- patterns.md - Extended patterns and recipes
- GNU Make 官方手册
- patterns.md - 扩展模式与脚本