make
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGNU Make
GNU Make
Purpose
用途
Guide agents through idiomatic Makefile patterns for C/C++ projects: phony targets, pattern rules, automatic dependency generation, and common build idioms.
指导开发者掌握C/C++项目中符合惯例的Makefile模式:伪目标、模式规则、自动依赖生成以及常见构建惯例。
Triggers
触发场景
- "How do I write a Makefile for my C project?"
- "My Makefile rebuilds everything every time"
- "How do I add dependency tracking to Make?"
- "What does ,
$@,$<mean?"$^ - "I'm getting 'make: Nothing to be done for all'"
- "How do I convert my shell compile script to a Makefile?"
- "如何为我的C项目编写Makefile?"
- "我的Makefile每次都会重新构建所有内容"
- "如何为Make添加依赖跟踪功能?"
- "、
$@、$<是什么意思?"$^ - "我遇到了'make: Nothing to be done for all'错误"
- "如何将我的Shell编译脚本转换为Makefile?"
Workflow
工作流程
1. Minimal correct Makefile for C
1. 适用于C项目的最简标准Makefile
makefile
CC := gcc
CFLAGS := -std=c11 -Wall -Wextra -g -O2
LDFLAGS :=
LDLIBS :=
SRCS := $(wildcard src/*.c)
OBJS := $(SRCS:src/%.c=build/%.o)
TARGET := build/prog
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
build/%.o: src/%.c | build
$(CC) $(CFLAGS) -c -o $@ $<
build:
mkdir -p build
clean:
rm -rf buildAutomatic variables:
- — target name
$@ - — first prerequisite
$< - — all prerequisites (deduplicated)
$^ - — stem (the
$*part in a pattern rule)% - — directory part of
$(@D)$@
makefile
CC := gcc
CFLAGS := -std=c11 -Wall -Wextra -g -O2
LDFLAGS :=
LDLIBS :=
SRCS := $(wildcard src/*.c)
OBJS := $(SRCS:src/%.c=build/%.o)
TARGET := build/prog
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
build/%.o: src/%.c | build
$(CC) $(CFLAGS) -c -o $@ $<
build:
mkdir -p build
clean:
rm -rf build自动变量:
- — 目标名称
$@ - — 第一个依赖项
$< - — 所有依赖项(去重后)
$^ - — 匹配符(模式规则中的
$*部分)% - —
$(@D)中的目录部分$@
2. Automatic dependency generation
2. 自动依赖生成
Without this, changing a header doesn't trigger a rebuild of files that include it.
.cmakefile
CC := gcc
CFLAGS := -std=c11 -Wall -Wextra -g -O2
DEPFLAGS = -MMD -MP # -MMD: generate .d file; -MP: phony targets for headers
SRCS := $(wildcard src/*.c)
OBJS := $(SRCS:src/%.c=build/%.o)
DEPS := $(OBJS:.o=.d)
TARGET := build/prog
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
build/%.o: src/%.c | build
$(CC) $(CFLAGS) $(DEPFLAGS) -MF $(@:.o=.d) -c -o $@ $<
-include $(DEPS) # '-' ignores errors on first build (no .d files yet)
build:
mkdir -p build
clean:
rm -rf build如果没有此功能,修改头文件不会触发包含该头文件的文件重新构建。
.cmakefile
CC := gcc
CFLAGS := -std=c11 -Wall -Wextra -g -O2
DEPFLAGS = -MMD -MP # -MMD: 生成.d文件; -MP: 为头文件创建伪目标
SRCS := $(wildcard src/*.c)
OBJS := $(SRCS:src/%.c=build/%.o)
DEPS := $(OBJS:.o=.d)
TARGET := build/prog
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
build/%.o: src/%.c | build
$(CC) $(CFLAGS) $(DEPFLAGS) -MF $(@:.o=.d) -c -o $@ $<
-include $(DEPS) # '-' 表示首次构建时忽略.d文件不存在的错误
build:
mkdir -p build
clean:
rm -rf build3. Pattern rules cheatsheet
3. 模式规则速查表
makefile
undefinedmakefile
undefinedCompile C
编译C文件
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
Compile C++
编译C++文件
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
Generate assembly
生成汇编代码
%.s: %.c
$(CC) $(CFLAGS) -S -o $@ $<
%.s: %.c
$(CC) $(CFLAGS) -S -o $@ $<
Run a tool on each file
对每个文件运行工具
build/%.processed: src/%.raw | build
mytool $< > $@
undefinedbuild/%.processed: src/%.raw | build
mytool $< > $@
undefined4. Common Make patterns
4. 常见Make模式
Debug and release builds
调试与发布构建
makefile
BUILD ?= release
ifeq ($(BUILD),debug)
CFLAGS += -g -Og -DDEBUG
else
CFLAGS += -O2 -DNDEBUG
endifUsage:
make BUILD=debugmakefile
BUILD ?= release
ifeq ($(BUILD),debug)
CFLAGS += -g -Og -DDEBUG
else
CFLAGS += -O2 -DNDEBUG
endif使用方式:
make BUILD=debugParallel builds
并行构建
bash
make -j$(nproc) # use all CPUs
make -j4 # exactly 4 jobsAdd (or ) for ordered output:
-Otarget-Omake -j$(nproc) -Obash
make -j$(nproc) # 使用所有CPU核心
make -j4 # 恰好运行4个任务添加(或)以按顺序输出:
-Otarget-Omake -j$(nproc) -OVerbose output
详细输出
makefile
undefinedmakefile
undefinedIn Makefile: suppress with @
在Makefile中:用@抑制命令输出
build/%.o: src/%.c | build
@echo " CC $<"
@$(CC) $(CFLAGS) -c -o $@ $<
Override silence: `make V=1` if you guard with `$(V)`:
```makefile
Q := $(if $(V),,@)
build/%.o: src/%.c
$(Q)$(CC) $(CFLAGS) -c -o $@ $<build/%.o: src/%.c | build
@echo " CC $<"
@$(CC) $(CFLAGS) -c -o $@ $<
如果用`$(V)`做判断,可以通过`make V=1`取消静默输出:
```makefile
Q := $(if $(V),,@)
build/%.o: src/%.c
$(Q)$(CC) $(CFLAGS) -c -o $@ $<Installing
安装
makefile
PREFIX ?= /usr/local
install: $(TARGET)
install -d $(DESTDIR)$(PREFIX)/bin
install -m 0755 $(TARGET) $(DESTDIR)$(PREFIX)/bin/makefile
PREFIX ?= /usr/local
install: $(TARGET)
install -d $(DESTDIR)$(PREFIX)/bin
install -m 0755 $(TARGET) $(DESTDIR)$(PREFIX)/bin/5. Multi-directory projects
5. 多目录项目
For medium projects, avoid recursive make (fragile, slow). Use a flat Makefile that includes sub-makefiles:
makefile
undefined对于中型项目,避免使用递归make(脆弱且缓慢)。使用一个顶层Makefile包含子Makefile:
makefile
undefinedproject/Makefile
project/Makefile
include lib/module.mk
include src/app.mk
```makefileinclude lib/module.mk
include src/app.mk
```makefilelib/module.mk
lib/module.mk
LIB_SRCS := $(wildcard lib/*.c)
LIB_OBJS := $(LIB_SRCS:lib/%.c=build/lib_%.o)
OBJS += $(LIB_OBJS)
build/lib_%.o: lib/%.c
$(CC) $(CFLAGS) -c -o $@ $<
undefinedLIB_SRCS := $(wildcard lib/*.c)
LIB_OBJS := $(LIB_SRCS:lib/%.c=build/lib_%.o)
OBJS += $(LIB_OBJS)
build/lib_%.o: lib/%.c
$(CC) $(CFLAGS) -c -o $@ $<
undefined6. Common errors
6. 常见错误
| Error | Cause | Fix |
|---|---|---|
| Missing source or rule | Check source path and pattern rule |
| Targets up to date | Touch a source file or run |
| Target depends on itself | Check dependency chain |
| Tab vs spaces | Recipes must use a tab, not spaces |
| Pattern rule syntax error | Check |
| Rebuilds everything every time | Timestamps wrong, or PHONY missing | Check |
| Header change not detected | No dep tracking | Add |
For a full variable and function reference, see references/cheatsheet.md.
| 错误信息 | 原因 | 解决方法 |
|---|---|---|
| 缺少源文件或规则 | 检查源文件路径和模式规则 |
| 所有目标均已更新 | 修改某个源文件或执行 |
| 目标依赖自身 | 检查依赖链 |
| 制表符与空格混淆 | 命令必须使用制表符,而非空格 |
| 模式规则语法错误 | 检查 |
| 每次都重新构建所有内容 | 时间戳错误,或缺少伪目标声明 | 检查系统时间;确保 |
| 修改头文件后未触发重新构建 | 未配置依赖跟踪 | 添加 |
完整的变量与函数参考,请查看references/cheatsheet.md。
Related skills
相关技能
- Use for CMake-based projects
skills/build-systems/cmake - Use for Ninja as a make backend
skills/build-systems/ninja - Use for CFLAGS details
skills/compilers/gcc
- 若项目基于CMake,请使用
skills/build-systems/cmake - 若将Ninja作为make的后端,请使用
skills/build-systems/ninja - 若需了解CFLAGS细节,请使用
skills/compilers/gcc