Makefile中缺失的include文件为何被自动追加.c后缀并触发编译?
我之前也踩过GNU Make这个坑!明明要include的.mak文件不存在,结果Make没按预期抛出"no such file or directory"错误,反而跑去触发编译.c文件的规则,完全偏离了我们的需求。
问题根源
GNU Make有个容易被忽略的默认行为:当你include一个不存在的文件时,它会把这个文件名视为待生成的目标,然后自动调用隐式规则尝试创建它。而默认隐式规则里包含了%: %.c——也就是只要存在对应的.c文件,就会用编译器编译生成目标文件。哪怕你的project_custom.mak.c根本不存在,Make也会触发这个规则的检查流程,导致你看到的异常编译行为。
解决方案
这里有两个靠谱的解决办法,你可以根据自己的场景选择:
方法1:提前检查文件是否存在(推荐)
在include之前,用wildcard函数检查目标文件是否存在,如果不存在直接抛出错误,不给隐式规则触发的机会:
PROJECT_CUSTOM_DIR := . CUSTOM_MAK_FILE := $(PROJECT_CUSTOM_DIR)/project_custom.mak # 检查文件是否存在,不存在则报错 ifeq ($(wildcard $(CUSTOM_MAK_FILE)),) $(error 错误:找不到必需的配置文件 $(CUSTOM_MAK_FILE)) endif include $(CUSTOM_MAK_FILE)
这个方法最精准,只会针对你指定的.mak文件做检查,不会影响Makefile里其他隐式规则的正常使用。
方法2:禁用所有隐式规则
如果你不需要依赖Make的任何默认隐式规则(比如所有编译规则都是自己手动定义的),可以直接关闭隐式规则功能:
- 调用Make时添加参数:
make --no-builtin-rules - 或者在Makefile开头加入:
MAKEFLAGS += --no-builtin-rules
这样Make就不会自动尝试生成不存在的include文件了,找不到时会直接抛出预期的"no such file or directory"错误。不过要注意,这个操作会禁用所有默认隐式规则,比如.c到.o的自动编译也会失效,只适合完全自定义编译规则的场景。
额外提醒
别用-include(带减号的include),它的作用是忽略不存在的文件且不报错,和你想要"找不到就报错"的需求完全相反。
内容的提问来源于stack exchange,提问作者solvingJ

