在 Makefile 中,规则模式(Pattern Rules)是一种非常有用的特性,它允许你为一组具有相似名称模式的目标文件定义通用的构建规则。这可以极大地简化 Makefile 的编写,并使得构建过程更加灵活和高效。
%.target: %.source
command
这里 % 表示一个或多个任意字符的占位符,target 和 source 分别代表目标文件和源文件的扩展名或其他特定的部分。
%.o: %.c
$(CC) -c $< -o $@
在这个例子中:
%
` 代表任意的文件名前缀。%.o
表示所有以 .o 结尾的目标文件。%.c
表示所有以 .c 结尾的源文件。$(CC)
` 是预定义的变量,通常表示编译器。-c
是编译选项,表示只编译不链接。$<
` 是自动变量,表示依赖文件(即源文件)。$@
` 也是自动变量,表示目标文件。
模式规则及注意事项
- 匹配顺序:如果一个目标文件同时符合多个模式规则,则 make 将使用最先匹配的规则。这意味着模式规则的顺序很重要。
- 依赖文件的匹配:依赖文件中的 % 字符会被替换为目标文件中相应部分的内容。
- 多级模式:可以使用多个 % 符号来定义更复杂的匹配模式。
- 模式规则与显式规则:如果一个目标同时被显式规则和模式规则指定,显式规则将优先。
项目实战
- 工程目录
├── Makefile
├── inc
│ ├── add.h
│ └── sub.h
└── src
├── add.c
├── main.c
└── sub.c- 其中,main.c包含sub.h、add.h,sub.c包含sub.h,add.c包含add.h。
Makefile
文件编写
# 编译器和编译选项
CC=gcc
CFLAGS=-Wall -Iinc
# 定义目标文件
SOURCES=src/main.c src/add.c src/sub.c
OBJS=$(SOURCES:.c=.o)
DEPS=$(SOURCES:.c=.d)
# 主目标
all: myapp
myapp: $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
# 规则模式
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# 生成依赖文件
%.d: %.c
$(CC) $(CFLAGS) -MM -MF $@ $<
#包含依赖文件
-include $(DEPS)
# 清理规则
clean:
rm -f $(OBJS) myapp $(DEPS)
- 解释
- 编译器和编译选项:
CC=gcc:设置编译器为 gcc。
CFLAGS=-Wall -Iinc:设置编译选项,包括警告级别和头文件搜索路径。 - 定义目标文件:
OBJS=$(patsubst %,src/%.o,$(notdir $(wildcard src/*.c)))
:
$(wildcard src/*.c)
:获取 src 目录下所有的 .c 文件。
$(notdir ...)
:去除文件路径中的目录部分,只保留文件名。
$(patsubst %,src/%.o,...)
:将每个 .c 文件名转换为 .o 文件名。 - 规则模式:
src/%.o: src/%.c
:定义了从.c
文件到.o
文件的转换规则。
%
作为占位符,表示任意的文件名前缀。
src/%.c
表示所有位于src
目录下的.c
文件。
src/%.o
表示相应的.o
文件。
$(CC) $(CFLAGS) -c $< -o $@
:编译命令。
$<
表示依赖文件(即源文件)。
$@
表示目标文件。 - 生成依赖
%.d: %.c:
规则模式,定义如何从 .c 文件生成 .d 文件。
(CFLAGS) -MM -MF $@ $<:
生成 .d 文件,其中 -MM 生成依赖文件,-MF 指定输出文件。
-include $(DEPS)
: 包含所有生成的 .d 文件,使 Make 能够自动处理依赖关系。 - 主目标:
all: myapp
:定义 all 目标,最终生成 myapp 可执行文件。
myapp: $(OBJS)
:定义 myapp 目标,依赖于所有 .o 文件。
$(CC) $(OBJS) -o $@
:链接命令,将所有的 .o 文件链接成一个可执行文件。 - 清理规则:
clean:
:定义 clean 目标,用于清理生成的文件。
rm -f $(OBJS) myapp
:删除所有的 .o 文件和 myapp 可执行文件。
- 编译器和编译选项: