跳到主要内容

Makefile 命令速查表

Makefile 是 C/C++ 项目和通用自动化构建的核心工具。GNU Make 通过 Makefile 定义目标、依赖和命令规则,实现增量构建和任务自动化。本速查表覆盖了编写 Makefile 最常用的语法和技巧,从基础变量和规则到高级函数和条件判断,每个示例都来自实际开发场景。

更新: 2026-07-16·40 条命令

快速参考

你要做什么用哪个语法
定义一个变量CC := gcc
引用一个变量$(CC) -o $@ $<
写一个编译规则%.o: %.c ; $(CC) -c $< -o $@
声明伪目标.PHONY: clean
查找所有 .c 文件$(wildcard src/*.c)
模式替换文件名$(patsubst %.c,%.o,$(wildcard *.c))
条件判断ifeq ($(OS),Linux)

变量定义

``makefile # 赋值方式 CC = gcc # 递归展开赋值(延迟求值) CC := gcc # 简单展开赋值(立即求值,推荐) CC ?= gcc # 条件赋值(仅当未定义时) CFLAGS += -Wall -O2 # 追加赋值 override CFLAGS += -g # 强制覆盖(即使命令行指定)

# 变量引用 $(CC) -o hello hello.c # 标准引用 ${CC} -o hello hello.c # 等价引用(花括号) $@ # 自动变量:当前目标名 $< # 自动变量:第一个依赖 $^ # 自动变量:所有依赖(去重) $+ # 自动变量:所有依赖(不去重) $* # 自动变量:模式匹配的 stem $? # 自动变量:比目标新的依赖

# 多行与 Shell 变量 define SCRIPT @echo "Running..." @echo "Done." endef

PATH := $(PATH):/usr/local/bin # 引用环境变量 SHELL := /bin/bash # 指定 shell(GNU make 默认 /bin/sh) `

目标规则

`makefile # 基本规则 target: prerequisites recipe # 注意:必须用 Tab 缩进,不能用空格

# 多依赖规则 app: main.o utils.o $(CC) -o $@ $^ @echo "Build complete: $@" # @ 前缀抑制命令回显

# 模式规则(最常用) %.o: %.c $(CC) -c $(CFLAGS) $< -o $@

%.o: %.c %.h # 带头文件依赖的模式规则 $(CC) -c $(CFLAGS) $< -o $@

# 多目标规则 obj1.o obj2.o: common.h # 多个目标依赖同一个文件

# 静态模式规则 objects = main.o utils.o $(objects): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@

# 双冒号规则(每次独立执行) clean:: rm -f *.o clean:: rm -f app # 多个 recipe,每个都执行

# 隐式规则链 # make 自动知道如何从 .c 构建 .o(使用内置规则) `

函数使用

`makefile # 文件匹配 SOURCES := $(wildcard src/*.c) # 匹配所有 .c 文件 OBJECTS := $(patsubst %.c,%.o,$(SOURCES)) # 将 .c 替换为 .o HEADERS := $(wildcard include/*.h) # 匹配头文件 OBJECTS := $(SOURCES:.c=.o) # 简写模式替换

# 字符串操作 FILES := foo.c bar.c baz.h $(filter %.c,$(FILES)) # 过滤出 .c 文件 $(filter-out %.h,$(FILES)) # 排除 .h 文件 $(basename foo.c) # 取文件名(不含扩展名) $(suffix foo.c) # 取扩展名 $(notdir src/main.c) # 取文件名部分 $(dir src/main.c) # 取目录部分

# 列表操作 $(addprefix obj/,$(OBJECTS)) # 给每个文件加前缀 $(addsuffix .bak,$(FILES)) # 给每个文件加后缀 $(words $(FILES)) # 统计单词数 $(word 2,$(FILES)) # 取第 2 个单词 $(firstword $(FILES)) # 取第一个单词 $(lastword $(FILES)) # 取最后一个单词

# 循环与执行 $(foreach src,$(SOURCES),$(info Processing $(src))) # 遍历处理

TAG := $(shell git describe --tags --always) # 执行 shell 命令 DATE := $(shell date +%Y-%m-%d) # 获取当前日期 $(shell mkdir -p build) # 创建目录(解析时执行) `

条件判断

`makefile # 变量值判断 ifeq ($(CC),gcc) CFLAGS += -std=c11 endif

ifneq ($(shell uname),Linux) CFLAGS += -D_POSIX_C_SOURCE=200809L endif

# 变量定义判断 ifdef DEBUG CFLAGS += -g -O0 -DDEBUG LDFLAGS += -fsanitize=address endif

ifndef RELEASE CFLAGS += -Wall -Wextra endif

# 多重条件 ifeq ($(OS),Windows_NT) RM := del /Q EXT := .exe else ifeq ($(shell uname),Darwin) RM := rm -f EXT := else RM := rm -f EXT := endif

# $(if) 函数(在变量展开时求值) CFLAGS := $(if $(DEBUG),-g -O0,-O2) # 条件选择值 LIBDIR := $(if $(wildcard /usr/local/lib),/usr/local/lib,/usr/lib) `

内置变量与隐式规则

`makefile # 常用内置变量 CC := cc # C 编译器 CXX := g++ # C++ 编译器 AR := ar # 归档器 CFLAGS := # C 编译器标志 CXXFLAGS := # C++ 编译器标志 LDFLAGS := # 链接器标志 LDLIBS := # 链接库(如 -lm) CPPFLAGS := # 预处理器标志(如 -Iinclude) RM := rm -f # 删除命令

# 内置隐式规则示例 # %.o: %.c — 使用 $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< # %.o: %.cc — 使用 $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< # %: %.c — 使用 $(CC) $(LDFLAGS) $< $(LDLIBS) -o $@ # %: %.o — 链接 .o 文件

# 覆盖隐式规则变量 .SUFFIXES: # 清空后缀列表 .SUFFIXES: .c .o .h # 只保留需要的后缀

# 特殊变量 $(MAKE) # make 自身(用于递归 make) $(MAKECMDGOALS) # 当前命令行目标 $(CURDIR) # 当前工作目录 $(MAKEFLAGS) # 当前 make 标志 $(.VARIABLES) # 所有已定义变量列表 $(.TARGETS) # 所有目标列表 `

伪目标与最佳实践

`makefile # 声明伪目标 .PHONY: all clean install test help lint dist

# 默认目标(放在第一个) all: app test # make 不带参数时执行

# 清理 clean: $(RM) $(OBJECTS) $(TARGET) $(RM) -r build/

# 安装 install: app @mkdir -p $(DESTDIR)/usr/local/bin cp $< $(DESTDIR)/usr/local/bin/ @echo "Installed to $(DESTDIR)/usr/local/bin/"

# 测试 test: app ./app --test @echo "All tests passed!"

# 帮助 help: @echo "Available targets:" @echo " all Build the project (default)" @echo " clean Remove build artifacts" @echo " install Install to \$$(DESTDIR)/usr/local/bin" @echo " test Run tests" @echo " lint Run code linting" @echo " dist Create distribution archive"

# 代码检查 lint: $(info Running linter...) $(shell command -v cppcheck >/dev/null || (echo "cppcheck not found" && exit 1)) cppcheck --enable=all $(SOURCES)

# 分发包 dist: $(info Creating distribution...) tar -czf $(TARGET)-$(TAG).tar.gz $(SOURCES) $(HEADERS) Makefile

# 最佳实践 Makefile 模板 CURRENT_DIR := $(notdir $(CURDIR)) TARGET := $(CURRENT_DIR) TAG := $(shell git describe --tags --always 2>/dev/null || echo "dev")

SOURCES := $(wildcard src/*.c) OBJECTS := $(SOURCES:.c=.o) HEADERS := $(wildcard include/*.h) CFLAGS := -Wall -Wextra -std=c11 -Iinclude LDFLAGS := LDLIBS := -lm

$(TARGET): $(OBJECTS) $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)

%.o: %.c $(HEADERS) $(CC) -c $(CFLAGS) -o $@ $<

.PHONY: all clean install test help all: $(TARGET) clean: ; $(RM) $(OBJECTS) $(TARGET) ``

变量定义(7)

命令难度
VAR := value
简单展开变量赋值(立即求值,推荐使用)
基础
VAR = value
递归展开变量赋值(延迟求值)
基础
VAR ?= value
条件赋值(仅在变量未定义时赋值)
中级
VAR += value
追加赋值到已有变量
基础
override VAR += value
强制覆盖变量(即使命令行指定了该变量)
中级
$(VAR) or ${VAR}
引用变量的值
基础
define VAR ... endef
定义多行变量(可用于复杂的 recipe)
中级

目标规则(6)

命令难度
target: prerequisites recipe
基本目标规则(依赖和命令)
基础
app: main.o utils.o $(CC) -o $@ $^
带多个依赖的编译规则
基础
%.o: %.c $(CC) -c $< -o $@
模式规则——将 .c 文件编译为 .o 文件
中级
$(objects): %.o: %.c $(CC) -c $< -o $@
静态模式规则,仅对指定文件列表应用模式
中级
target:: prerequisites
双冒号规则(每个 recipe 都独立执行)
高级
@echo 'Building...'
静默执行命令(@ 前缀抑制命令回显)
基础

函数使用(7)

命令难度
$(wildcard pattern)
匹配实际存在的文件列表
基础
$(patsubst %.c,%.o,$(SOURCES))
模式字符串替换(将 .c 替换为 .o)
中级
$(shell command)
执行 shell 命令并返回输出
中级
$(filter pattern,text)
从列表中过滤出匹配模式的文件
中级
$(foreach var,list,text)
遍历列表并对每一项执行文本扩展
中级
$(addprefix prefix,names)
给列表中的每个文件添加前缀路径
中级
$(notdir path)
从文件路径中提取文件名部分
基础

条件判断(6)

命令难度
ifeq (arg1, arg2) ... endif
条件判断——比较两个值是否相等
基础
ifneq (arg1, arg2) ... endif
条件判断——比较两个值是否不相等
基础
ifdef VAR ... endif
检查变量是否已定义
基础
ifndef VAR ... endif
检查变量是否未定义
基础
ifeq ... else ifeq ... else ... endif
多重条件分支判断
中级
$(if condition,then-part,else-part)
$(if) 函数——在变量展开时做条件选择
中级

内置变量与隐式规则(6)

命令难度
$(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS)
常用的内置编译相关变量
基础
$(MAKE)
make 自身的变量(用于递归调用 make)
中级
$(MAKECMDGOALS)
当前命令行中指定的目标列表
中级
$(CURDIR)
当前工作目录的绝对路径
基础
$(.VARIABLES)
所有已定义的变量列表(用于调试)
高级
$(MAKEFLAGS)
当前 make 的 flags 变量
中级

伪目标与最佳实践(8)

命令难度
.PHONY: target1 target2
声明伪目标(不表示实际文件)
基础
clean: rm -f *.o $(TARGET)
清理编译产物的 clean 目标
基础
all: target1 target2
默认目标(make 不带参数时执行的第一个目标)
基础
install: app cp $< $(DESTDIR)/usr/local/bin/
安装目标——将构建产物复制到系统目录
中级
test: app ./app --test
测试目标——运行测试用例
基础
help: @echo 'Available targets...'
帮助目标——列出所有可用的目标及说明
中级
$(info message)
在解析时打印调试信息
中级
$(error message)
在解析时打印错误信息并终止构建
中级

常见问题

本速查表数据整理自各工具官方文档。最后更新: 2026-07-16。