You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合并Makefile目标?合并失败原因及解决方法

Makefile目标规则合并错误分析与解决

问题背景

原有一段可正常运行的Makefile代码,尝试合并其中的目标规则后,执行时出现报错:gcc: error: toto.c no such file or directory。

原可运行代码

c_file_path := toto.c
asm_file_path := toto.S

c_files = $(notdir $(c_file_path)) 
asm_files = $(notdir $(asm_file_path)) 

vpath %.c $(dir $(c_file_path)) 
vpath %.S $(dir $(asm_file_path))

OBJDIR=objs/
c_objs:=$(addprefix $(OBJDIR),$(patsubst %.c,%.o,$(c_files)))
asm_objs:=$(addprefix $(OBJDIR),$(patsubst %.S,%.S.o,$(asm_files)))

$(info c_files $(c_files))
$(info s_files $(asm_files))
$(info c_objs $(c_objs))
$(info asm_objs $(asm_objs))

%.c:
    @touch $@
%.S:
    @touch $@

objs/%.o:%.c
    @mkdir -p  $(OBJDIR)
    @gcc -c $^ -o $@

objs/%.S.o:%.S
    @mkdir -p  $(OBJDIR)
    @gcc -c $^ -o $@

clean:
    @rm -rf objs/*
    
all: $(c_objs) $(asm_objs)
    @ls $(c_objs) $(asm_objs)
    @echo "hello"

修改后的错误代码

c_file_path := toto.c
asm_file_path := toto.S

c_files = $(notdir $(c_file_path)) 
asm_files = $(notdir $(asm_file_path)) 

vpath %.c $(dir $(c_file_path)) 
vpath %.S $(dir $(asm_file_path))

OBJDIR=objs/
c_objs:=$(addprefix $(OBJDIR),$(patsubst %.c,%.o,$(c_files)))
asm_objs:=$(addprefix $(OBJDIR),$(patsubst %.S,%.S.o,$(asm_files)))

$(info c_files $(c_files))
$(info s_files $(asm_files))
$(info c_objs $(c_objs))
$(info asm_objs $(asm_objs))

%.c %.S:
    @touch $@

objs/%.o objs/%.S.o:%.c %.S
    @mkdir -p  $(OBJDIR)
    @gcc -c $^ -o $@

clean:
    @rm -rf objs/*
    
all: $(c_objs) $(asm_objs)
    @ls $(c_objs) $(asm_objs)
    @echo "hello"

报错信息

gcc: error: toto.c no such file or directory

错误原因

问题出在编译规则的合并方式错误:

  1. 依赖关联错误:objs/%.o objs/%.S.o:%.c %.S这种多目标多依赖的写法,会让每个目标同时绑定%.c和%.S两个依赖。比如构建objs/toto.o时,Make会认为它需要toto.c和toto.S;构建objs/toto.S.o时,会错误地认为它需要toto.c和toto.S(实际只需要toto.S)。
  2. 命令参数错误:$^会展开所有依赖文件,导致gcc尝试同时编译两个源文件,不符合单文件编译的需求。
  3. 模式匹配歧义:对于objs/%.S.o目标,%会匹配toto,进而依赖toto.c,但该文件要么未触发生成规则,要么根本不需要,最终导致gcc找不到文件。

正确的目标合并方法

1. 共享命令的模式规则合并

将两个编译规则的目标-依赖对分别列出,共享同一组命令,Make会自动为每个目标匹配对应的依赖:

objs/%.o: %.c
objs/%.S.o: %.S
	@mkdir -p $(OBJDIR)
	@gcc -c $^ -o $@

这种写法既实现了代码复用,又保证每个目标只依赖对应的源文件,$^会正确展开为单个依赖文件。

2. 静态模式规则合并

如果明确知道目标列表,用静态模式规则更清晰,直接绑定目标与对应的源文件模式:

$(c_objs): objs/%.o: %.c
$(asm_objs): objs/%.S.o: %.S
	@mkdir -p $(OBJDIR)
	@gcc -c $^ -o $@

这种方式避免了模式匹配的歧义,适合目标列表固定的场景。

修正后的完整Makefile

c_file_path := toto.c
asm_file_path := toto.S

c_files = $(notdir $(c_file_path)) 
asm_files = $(notdir $(asm_file_path)) 

vpath %.c $(dir $(c_file_path)) 
vpath %.S $(dir $(asm_file_path))

OBJDIR=objs/
c_objs:=$(addprefix $(OBJDIR),$(patsubst %.c,%.o,$(c_files)))
asm_objs:=$(addprefix $(OBJDIR),$(patsubst %.S,%.S.o,$(asm_files)))

$(info c_files $(c_files))
$(info s_files $(asm_files))
$(info c_objs $(c_objs))
$(info asm_objs $(asm_objs))

%.c %.S:
	@touch $@

# 正确合并的编译规则
objs/%.o: %.c
objs/%.S.o: %.S
	@mkdir -p $(OBJDIR)
	@gcc -c $^ -o $@

clean:
	@rm -rf objs/*

all: $(c_objs) $(asm_objs)
	@ls $(c_objs) $(asm_objs)
	@echo "hello"

内容的提问来源于stack exchange,提问作者Guillaume D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 21:01:04