SuperAPI AI 工具集

make

编程与开发

查看项目

更新于 10-15 18:06

技能介绍

用途

本技能引导智能体掌握 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: 生成 .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. 模式规则速查

# 编译 C
%.o: %.c
	$(CC) $(CFLAGS) -c -o $@ $<

# 编译 C++
%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c -o $@ $<

# 生成汇编
%.s: %.c
	$(CC) $(CFLAGS) -S -o $@ $<

# 对每个文件运行工具
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)     # 使用所有 CPU
make -j4            # 恰好 4 个任务

添加 -Otarget(或 -O)可让输出有序:make -j$(nproc) -O

详细输出:

# 在 Makefile 中:用 @ 抑制回显
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 检查日期;确保 all 是 .PHONY
头文件变更未被检测 没有依赖跟踪 添加 -MMD -MP 和 -include $(DEPS)

完整的变量与函数参考见 references/cheatsheet.md。

相关技能

  • CMake 项目请使用 skills/build-systems/cmake
  • 将 Ninja 作为 make 后端请使用 skills/build-systems/ninja
  • CFLAGS 细节请使用 skills/compilers/gcc