GNU Makefile依赖已构建但目标需重执行才编译的问题排查
Make构建依赖生成后不执行目标规则的问题分析
问题现象
- 首次执行
make时会报错file not found: src/cross-tile.o,但再次执行make即可完成完整构建 - 在src目录执行
make TARGET_CC=cc ../src/cross-tile.o,首次执行仅会生成依赖文件tile.c(通过运行tilemap工具生成),不会编译生成cross-tile.o;第二次执行该命令则会成功生成目标文件
复现步骤
- 克隆仓库后执行
sh sys/android/setup.sh(仅完成Makefile的复制操作) - 进入src目录执行
make TARGET_CC=cc ../src/cross-tile.o,观察首次执行的输出结果 - 再次执行上述命令,确认
cross-tile.o是否生成
关键配置与规则
项目中TARGETPFX变量设置为../src/cross-,最初使用的是以下隐式规则组合:
# 仅声明目标依赖,未指定编译命令 $(TARGETPFX)tile.o: ../src/tile.c # 通用的.c文件编译为.o文件的隐式规则 %.o: %.c $(TARGET_CC) -c -o $@ $<
将其修改为显式规则后,问题得到解决:
$(TARGETPFX)tile.o: ../src/tile.c $(TARGET_CC) -c -o $(TARGETPFX)tile.o ../src/tile.c
原因分析
问题的核心在于Make的隐式规则匹配逻辑和仅依赖声明规则的行为:
- 原配置中的
$(TARGETPFX)tile.o: ../src/tile.c只是一个依赖声明——它仅告知Make../src/cross-tile.o依赖于../src/tile.c,但没有提供生成目标文件的具体编译命令。 - 首次执行时,Make检测到
../src/tile.c不存在,会优先执行生成该依赖的规则(通过项目中的tilemap工具生成tile.c)。 - 当
tile.c生成完成后,Make需要寻找能编译生成../src/cross-tile.o的规则,但默认的%.o: %.c隐式规则有严格的文件名匹配要求:目标文件的主名称(如cross-tile)必须与依赖的.c文件主名称(如tile)完全一致。也就是说,该隐式规则只会尝试寻找../src/cross-tile.c来编译生成目标,但实际存在的是../src/tile.c,因此规则完全不匹配,Make找不到可执行的编译命令。 - 首次执行时,Make在完成依赖生成后不会重新触发规则扫描与匹配逻辑,因此直接终止流程,
cross-tile.o未被生成。而修改为显式规则后,我们直接指定了编译命令,强制使用../src/tile.c来编译生成../src/cross-tile.o,完全绕过了隐式规则的文件名匹配限制,因此无论首次还是后续执行,都能正常生成目标文件。
内容的提问来源于stack exchange,提问作者JodiJodington
相关产品推荐
相关产品推荐

