关于 make
面向 Agent 的 GNU Make 技能,帮助编写和排查 C/C++ 项目的 Makefile。内容包括依赖跟踪、模式规则、构建配置和多目录项目组织。
主要功能
- 01C/C++ Makefile 基础模式
- 02自动依赖生成与跟踪
- 03模式规则和自动变量
- 04调试与发布构建配置
- 05并行构建与安装规则
- 06多目录项目组织方式
适用场景
- 01为 C 项目编写 Makefile
- 02修复头文件变更未触发重建
- 03排查重复构建或规则错误
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill make安装后在 Claude Code 中输入/make确认已加载。
附带文件references/cheatsheet.md
详细介绍
GNU Make
用途
指导 Agent 为 C/C++ 项目编写符合惯例的 Makefile,包括伪目标、模式规则、自动依赖生成和常见构建惯用写法。
触发场景
- “如何为我的 C 项目编写 Makefile?”
- “我的 Makefile 每次都会重新构建所有内容”
- “如何在 Make 中添加依赖跟踪?”
- “
$@、$<、$^分别是什么意思?” - “我遇到了 ‘make: Nothing to be done for all’”
- “如何将我的 shell 编译脚本转换为 Makefile?”
工作流
1. 正确的最简 C 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. 自动生成依赖
如果没有这项设置,修改头文件不会触发包含该头文件的 .c 文件重新构建。
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
3. 模式规则速查表
# Compile C
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
# Compile C++
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
# Generate assembly
%.s: %.c
$(CC) $(CFLAGS) -S -o $@ $<
# Run a tool on each file
build/%.processed: src/%.raw | build
mytool $< > $@
4. 常见 Make 写法
调试和发布构建
BUILD ?= release
ifeq ($(BUILD),debug)
CFLAGS += -g -Og -DDEBUG
else
CFLAGS += -O2 -DNDEBUG
endif
用法:make BUILD=debug
并行构建
make -j$(nproc) # use all CPUs
make -j4 # exactly 4 jobs
添加 -Otarget(或 -O)以按顺序显示输出:make -j$(nproc) -O
详细输出
# In Makefile: suppress with @
build/%.o: src/%.c | build
@echo " CC $<"
@$(CC) $(CFLAGS) -c -o $@ $<
如果使用 $(V) 进行条件判断,可通过 make V=1 覆盖静默设置:
Q := $(if $(V),,@)
build/%.o: src/%.c
$(Q)$(CC) $(CFLAGS) -c -o $@ $<
安装
PREFIX ?= /usr/local
install: $(TARGET)
install -d $(DESTDIR)$(PREFIX)/bin
install -m 0755 $(TARGET) $(DESTDIR)$(PREFIX)/bin/
5. 多目录项目
对于中型项目,避免使用递归 make(容易出错且速度慢)。使用包含子 Makefile 的扁平 Makefile:
# project/Makefile
include lib/module.mk
include src/app.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 $@ $<
6. 常见错误
| 错误 | 原因 | 修复方法 |
|---|---|---|
No rule to make target 'foo.o' | 缺少源文件或规则 | 检查源文件路径和模式规则 |
Nothing to be done for 'all' | 目标已是最新状态 | 修改源文件的时间戳,或运行 make clean |
Circular dependency dropped | 目标依赖于自身 | 检查依赖链 |
missing separator | 使用了空格而非制表符 | 命令必须以制表符开头,而非空格 |
*** multiple target patterns | 模式规则语法错误 | 检查 % 的位置 |
| 每次都重新构建所有内容 | 时间戳错误,或缺少 PHONY | 检查 date;确保 all 是 .PHONY |
| 未检测到头文件变更 | 未跟踪依赖 | 添加 -MMD -MP 和 -include $(DEPS) |
完整的变量和函数参考请参阅 references/cheatsheet.md。
相关技能
- 对于基于 CMake 的项目,请使用
skills/build-systems/cmake - 对于将 Ninja 用作 make 后端的项目,请使用
skills/build-systems/ninja - 有关 CFLAGS 的详细信息,请使用
skills/compilers/gcc
评论
支持 Markdown