GNU Make 3.82适配:无.c文件时从.s生成.o的规则兼容问题
解决GNU Make 3.82中.s文件生成.o的规则冲突问题
这个问题我之前也碰到过,核心原因是GNU Make 3.82对隐式规则的搜索逻辑做了调整:当你定义了%.c → %.s和%.s → %.o两条模式规则时,3.82版本会优先尝试走完整的c→s→o依赖链——哪怕你已经有现成的.s文件,它还是会去检查对应的.c文件是否存在,找不到就直接报错。而3.81版本则会跳过这条无效的链,直接用已有的.s文件生成.o。
这里有几个实用的修复方案,你可以根据自己的Makefile结构选择:
方案1:将.c→.s规则改为静态模式(推荐)
把全局的%.s: %.c模式规则,改成只针对你真正需要从.c生成.s的文件。比如你有一个CSRCS变量存放所有.c源文件,就可以这样写:
# 假设CSRCS是你的.c源文件列表 $(CSRCS:.c=.s): %.s: %.c $(CC) $(CFLAGS) -o $@ -S $< %.o: %.s $(CC) $(CFLAGS) -o $@ -c $< all:: $(OBJS)
这样这条规则只会作用于有对应.c文件的.s目标,当没有.c文件时,make不会触发这条规则,自然就会直接用现成的.s文件生成.o了。
方案2:显式处理.s对应的.o文件
先找出所有已存在的.s文件,为它们对应的.o单独定义规则,剩下的.o再用常规规则处理:
# 找出当前目录下所有.s文件,转换成对应的.o文件名 S_OBJS := $(patsubst %.s,%.o,$(wildcard *.s)) # 为这些.o文件单独定义从.s生成的规则 $(S_OBJS): %.o: %.s $(CC) $(CFLAGS) -o $@ -c $< # 剩下的.o文件用.c生成(如果需要的话) C_OBJS := $(filter-out $(S_OBJS),$(OBJS)) $(C_OBJS): %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< all:: $(OBJS)
这种方式更直白,直接告诉make哪些.o要从.s生成,彻底避免了隐式规则的冲突。
方案3:标记.s文件为非中间文件
通过.NOTINTERMEDIATE告诉make,.s文件是最终文件,不要把它们当作需要生成的中间文件:
# 把所有OBJS对应的.s文件标记为非中间文件 .NOTINTERMEDIATE: $(OBJS:.o=.s) %.s: %.c $(CC) $(CFLAGS) -o $@ -S $< %.o: %.s $(CC) $(CFLAGS) -o $@ -c $< all:: $(OBJS)
这样make就不会试图去生成这些.s文件,只会直接使用已有的文件来构建.o。
内容的提问来源于stack exchange,提问作者Shuang Han




