GNU Make含双重后缀文件无法识别模式规则问题咨询
我编写了一个仅包含如下模式规则的极简Makefile:
%: %.m4 m4 $< > $@
使用GNU Make测试时:
- 执行
touch foo.in.m4 ; make foo.in可正常运行,生成命令为m4 foo.in.m4 > foo.in; - 但对于带双重后缀的
foo.sh.m4,执行touch foo.sh.m4; make foo.sh时提示:*** No rule to make target 'foo.sh'。
类似问题还出现在.f、.c、.o、.tex、.dvi等后缀,但.xml、.doc、.mp3等多数后缀可正常工作。测试脚本如下:
for suff in pdf sh f c o xml doc docx tex dvi mp3 png odt txt in none yxn; do touch foo.$suff.m4 make foo.$suff done
使用 make -r 可正常运行,推测与默认后缀列表有关,但添加空规则 .SUFFIXES: 后,情况有所改善但仍存在.c和.tex后缀的问题,即存在 bar.c.in 和 bar.tex.in 时,make bar.c 和 make bar.tex 仍提示无规则。
我原以为后缀列表仅与后缀规则相关,与模式规则无关,想请教这一现象的原因。
你的核心误解在于:GNU Make的.SUFFIXES后缀列表及内置隐含规则,并非仅作用于传统后缀规则,还会直接影响模式规则的匹配优先级与逻辑。具体原因分以下几点:
内置隐含规则的优先级抢占
GNU Make默认加载了大量内置隐含规则,针对.c、.sh、.tex这类常见后缀,存在对应的生成规则(比如.c文件可从.i预处理文件生成,.tex可从相关辅助文件生成)。当你执行make foo.sh或make foo.c时,Make会优先尝试匹配这些内置隐含规则,而非你自定义的%: %.m4模式规则。若存在部分依赖文件(比如你提到的bar.c.in),Make会尝试用对应隐含规则生成目标,而非匹配你的.m4规则。后缀列表对模式匹配的影响
.SUFFIXES定义的后缀列表会改变Make对目标文件名的拆分逻辑。对于列表中的后缀,Make会将目标视为「基名+后缀」的组合,优先尝试匹配针对该后缀的规则(包括后缀规则和隐含模式规则),而不是直接将整个目标名匹配到你的%模式中。比如.sh在默认后缀列表里,Make会把foo.sh拆分为基名foo+后缀.sh,然后寻找能生成.sh后缀文件的规则,而非直接匹配%为foo.sh的自定义规则。make -r与.SUFFIXES:的差异
make -r会完全禁用所有内置隐含规则,此时Make只能依赖你定义的规则,因此所有后缀的目标都能正常匹配%: %.m4。- 添加空的
.SUFFIXES:仅清空了默认后缀列表,但并未禁用所有内置隐含模式规则(比如%.c: %.i、%.tex: %.tex.in这类规则依然存在)。当存在bar.c.in时,Make会匹配这类隐含规则尝试生成bar.c,但因依赖或命令不完整最终报错,而非匹配你的.m4规则。
如果想让自定义的%: %.m4规则优先生效,可以采取以下两种方式:
- 直接使用
make -r命令,彻底禁用所有内置隐含规则; - 在Makefile中添加
.SUFFIXES:清空后缀列表,同时加上MAKEFLAGS += -r来禁用内置隐含规则,确保自定义规则成为唯一选择。
内容的提问来源于stack exchange,提问作者nwcyclist

