make

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

GNU 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 build
Automatic variables:
  • $@
    — target name
  • $<
    — first prerequisite
  • $^
    — all prerequisites (deduplicated)
  • $*
    — stem (the
    %
    part in a pattern rule)
  • $(@D)
    — directory part of
    $@
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
.c
files that include it.
makefile
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
如果没有此功能,修改头文件不会触发包含该头文件的
.c
文件重新构建。
makefile
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 build

3. Pattern rules cheatsheet

3. 模式规则速查表

makefile
undefined
makefile
undefined

Compile 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 $< > $@
undefined
build/%.processed: src/%.raw | build mytool $< > $@
undefined

4. Common Make patterns

4. 常见Make模式

Debug and release builds

调试与发布构建

makefile
BUILD ?= release

ifeq ($(BUILD),debug)
  CFLAGS += -g -Og -DDEBUG
else
  CFLAGS += -O2 -DNDEBUG
endif
Usage:
make BUILD=debug
makefile
BUILD ?= release

ifeq ($(BUILD),debug)
  CFLAGS += -g -Og -DDEBUG
else
  CFLAGS += -O2 -DNDEBUG
endif
使用方式:
make BUILD=debug

Parallel builds

并行构建

bash
make -j$(nproc)     # use all CPUs
make -j4            # exactly 4 jobs
Add
-Otarget
(or
-O
) for ordered output:
make -j$(nproc) -O
bash
make -j$(nproc)     # 使用所有CPU核心
make -j4            # 恰好运行4个任务
添加
-Otarget
(或
-O
)以按顺序输出:
make -j$(nproc) -O

Verbose output

详细输出

makefile
undefined
makefile
undefined

In 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
undefined

project/Makefile

project/Makefile

include lib/module.mk include src/app.mk

```makefile
include lib/module.mk include src/app.mk

```makefile

lib/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 $@ $<
undefined
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 $@ $<
undefined

6. Common errors

6. 常见错误

ErrorCauseFix
No rule to make target 'foo.o'
Missing source or ruleCheck source path and pattern rule
Nothing to be done for 'all'
Targets up to dateTouch a source file or run
make clean
Circular dependency dropped
Target depends on itselfCheck dependency chain
missing separator
Tab vs spacesRecipes must use a tab, not spaces
*** multiple target patterns
Pattern rule syntax errorCheck
%
placement
Rebuilds everything every timeTimestamps wrong, or PHONY missingCheck
date
; ensure
all
is
.PHONY
Header change not detectedNo dep trackingAdd
-MMD -MP
and
-include $(DEPS)
For a full variable and function reference, see references/cheatsheet.md.
错误信息原因解决方法
No rule to make target 'foo.o'
缺少源文件或规则检查源文件路径和模式规则
Nothing to be done for 'all'
所有目标均已更新修改某个源文件或执行
make clean
Circular dependency dropped
目标依赖自身检查依赖链
missing separator
制表符与空格混淆命令必须使用制表符,而非空格
*** multiple target patterns
模式规则语法错误检查
%
的位置
每次都重新构建所有内容时间戳错误,或缺少伪目标声明检查系统时间;确保
all
被声明为
.PHONY
修改头文件后未触发重新构建未配置依赖跟踪添加
-MMD -MP
参数并使用
-include $(DEPS)
完整的变量与函数参考,请查看references/cheatsheet.md

Related skills

相关技能

  • Use
    skills/build-systems/cmake
    for CMake-based projects
  • Use
    skills/build-systems/ninja
    for Ninja as a make backend
  • Use
    skills/compilers/gcc
    for CFLAGS details
  • 若项目基于CMake,请使用
    skills/build-systems/cmake
  • 若将Ninja作为make的后端,请使用
    skills/build-systems/ninja
  • 若需了解CFLAGS细节,请使用
    skills/compilers/gcc