为何未编写显式规则时Makefile仍能自动生成目标文件?
Make自动编译源文件的原理与适用场景
为什么没写显式规则也能生成目标文件?
你遇到的情况是make内置隐含规则在起作用。GNU Make(最常用的make实现)自带了一系列预定义的模式规则,用来处理常见的编译任务,比如把.c文件编译成.o目标文件,不需要你手动写每个源文件的编译规则。
核心原理:隐含规则的匹配与执行
make的隐含规则基于模式匹配和预定义变量工作:
- 模式匹配:内置规则用
%作为通配符,比如最常用的%.o: %.c,意思是“任何.o目标都可以通过对应的.c源文件生成”。当make发现某个.o文件不存在,且没有显式规则定义它的生成方式时,会自动匹配这个模式。 - 预定义编译命令:make预定义了一系列变量控制编译行为,比如:
CC:默认是系统的C编译器(通常是cc或gcc)COMPILE.c:默认是$(CC) $(CFLAGS) $(CPPFLAGS) -c,这就是生成.o文件的核心命令
当匹配到%.o: %.c规则时,make会用这些变量拼接出具体的编译命令,比如cc -c lorem.c -o lorem.o。
你的共享库案例具体流程
假设你的Makefile只写了共享库的链接规则:
libfoo.so: lorem.o ipsum.o cc -shared -o $@ $^
执行make libfoo.so时的完整流程:
- make检查目标
libfoo.so的依赖lorem.o和ipsum.o是否存在 - 发现这两个
.o文件不存在,且没有显式规则定义它们的生成方式 - 搜索内置规则,匹配到
%.o: %.c,确认对应的lorem.c和ipsum.c存在 - 调用内置编译命令,分别生成
lorem.o和ipsum.o - 最后执行共享库的链接命令,生成
libfoo.so
隐含规则的适用场景
本次案例场景
构建共享库/静态库时,只需定义库文件的依赖列表(所有.o文件),不需要为每个源文件写编译规则,大大简化Makefile的长度。
一般通用场景
- 常规可执行文件构建:比如写
myapp: main.o utils.o,make会自动编译main.c和utils.c - 统一编译参数:通过修改预定义变量(比如
CFLAGS = -O2 -Wall),可以一次性给所有编译任务添加参数,不需要逐个规则修改 - 快速原型开发:小项目中不用写复杂的Makefile,只定义最终目标即可完成编译
自定义与覆盖
如果内置规则不符合你的需求:
- 修改预定义变量:比如用交叉编译器时,设置
CC = arm-linux-gnueabihf-gcc,所有隐含规则都会自动使用这个编译器 - 自定义模式规则:比如写
%.o: %.c并定义自己的命令,会覆盖内置规则 - 显式规则优先:如果为某个特定文件写了显式规则(比如
lorem.o: lorem.c),make会优先使用你的显式规则,而不是内置规则
内容的提问来源于stack exchange,提问作者StoneThrow
相关产品推荐
相关产品推荐

