新手用Makefile编译多二进制报错:No rule to make target s1_c1.o
问题解决:编译多二进制程序的Makefile修正
你的报错核心原因是目标依赖的.o文件路径不匹配:s1_c1.o指向当前目录的对象文件,但你的源文件./challenges/s1_c1.c生成的对象文件是./challenges/s1_c1.o,Make找不到当前目录下的s1_c1.c来生成s1_c1.o,所以报错。
以下是修正后的完整Makefile:
# 二进制程序名称 BINARY=s1_c1 s1_c2 s1_c3 # 输出目录 BINDIR=./bin CODEDIRS=./challenges ./src INCDIRS=. ./include/ COMPILER=gcc OPT=-O2 DEBUG=-Og DEPFLAGS=-MP -MD CFLAGS1=-Wall -g $(foreach D, $(INCDIRS), -I$(D)) $(DEBUG) $(DEPFLAGS) CFLAGS2=-Wall $(foreach D, $(INCDIRS), -I$(D)) $(DEPFLAGS) # 所有C源文件 CFILES=$(foreach D, $(CODEDIRS), $(wildcard $(D)/*.c)) # challenges目录下的主程序源文件 MAINCFILES=$(filter ./challenges/%, $(CFILES)) # 所有对象文件 OBJECTS=$(patsubst %.c,%.o,$(CFILES)) # challenges目录下的主程序对象文件 MAINOBJECTS=$(filter ./challenges/%, $(OBJECTS)) # src目录下的库对象文件 LIBOBJECTS=$(filter ./src/%, $(OBJECTS)) # 依赖文件 DEPFILES=$(patsubst %.c,%.d,$(CFILES)) # 确保bin目录存在 $(BINDIR): mkdir -p $@ # 所有目标:先创建bin目录,再生成二进制程序 all: $(BINDIR) $(addprefix $(BINDIR)/, $(BINARY)) .PHONY: all clean # 批量生成二进制程序规则:每个二进制依赖库对象和对应的主程序对象 $(BINDIR)/%: $(LIBOBJECTS) ./challenges/%.o $(COMPILER) -o $@ $^ # 通用编译规则:从.c生成.o %.o: %.c $(COMPILER) $(CFLAGS1) -c -o $@ $< # 包含依赖文件,自动处理头文件变化 -include $(DEPFILES) clean: rm -rf $(BINDIR) $(OBJECTS) $(DEPFILES)
关键修改点说明:
- 路径匹配修正:将二进制目标的依赖从
s1_c1.o改为./challenges/s1_c1.o,同时用$(BINDIR)/%和./challenges/%.o的模式匹配,批量处理所有二进制程序,避免重复写规则。 - 输出目录处理:新增
$(BINDIR)目标确保bin目录存在,所有二进制程序生成到./bin目录下。 - 编译命令错误修复:把
(-o)改成正确的-o。 - 简化变量逻辑:用
filter替代复杂的foreach+if,直接筛选目录下的文件,更简洁高效。 - 依赖文件引入:添加
-include $(DEPFILES),让Make自动处理头文件修改后的重编译。 - clean规则更新:删除bin目录,同时清理所有对象文件(包括challenges下的.o)。
额外优化建议:
如果需要区分主程序和库文件的编译参数,可以给主程序对象单独写规则:
./challenges/%.o: ./challenges/%.c $(COMPILER) $(CFLAGS2) -c -o $@ $<
这样主程序用CFLAGS2,库文件用CFLAGS1编译。
内容的提问来源于stack exchange,提问作者RB1
相关产品推荐
相关产品推荐

