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

递归搜索子目录源文件时Makefile报“No rule to make target...”错误

问题描述

尝试为Windows下Code::Blocks创建的多子目录大型项目编写Linux Makefile,运行时持续报错:

make: *** No rule to make target 'cKeyboard.o', needed by '/home/buster/MyProject/LINUXmake/bin-arm/MyProject'.  Stop.

执行show目标后可见,生成的Object files列表仅包含文件名(如cKeyboard.o),而非预期的~/MyProject/LINUXmake/obj-arm/cKeyboard.o,同时编译规则无法关联子目录中的源文件。


问题根源分析

  1. 目标文件路径错误:原Makefile中$(notdir $(SRC:.c=.o))丢弃了源文件的目录信息,后续patsubst未正确为目标文件添加OBJ_PATH前缀,导致make认为需要在当前目录生成cKeyboard.o,但无对应规则。
  2. 编译规则无法匹配源文件:原有的%.o: %.c模式规则默认源文件与目标文件在同一目录,但实际源文件分散在各个子目录,规则无法定位到正确的源文件位置。
  3. 重复目标冲突:源目录中存在24cXX.c和24cXX.cpp,会生成同名的24cXX.o,导致编译冲突。

修复后的完整Makefile

# 主项目文件夹
MyProject_PATH := ~/MyProject/
# 主源文件文件夹
SRC_PATH := $(MyProject_PATH)src
# 所有源文件子目录
SRC_DIRS := $(shell find $(SRC_PATH) -type d)

# 输出文件夹
OBJ_PATH := $(MyProject_PATH)LINUXmake/obj-arm
BIN_PATH := $(MyProject_PATH)LINUXmake/bin-arm
# 最终可执行文件名
EXE      := $(BIN_PATH)/MyProject-arm

# 获取所有.c和.cpp文件
SRC   := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cpp))
# 为每个源文件定义目标文件:OBJ_PATH下的同名.o文件
OBJ := $(addprefix $(OBJ_PATH)/,$(notdir $(SRC:.c=.o)))
OBJ := $(addprefix $(OBJ_PATH)/,$(notdir $(OBJ:.cpp=.o)))

# 定义源文件搜索路径,让make能找到子目录中的源文件
vpath %.c $(SRC_DIRS)
vpath %.cpp $(SRC_DIRS)

.PHONY: all show clean

# 默认构建目标
all: $(EXE)

# 编译.c文件规则:目标文件在OBJ_PATH,源文件通过vpath查找
$(OBJ_PATH)/%.o: %.c
	@echo "Compiling C file: $<"
	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

# 编译.cpp文件规则:目标文件在OBJ_PATH,源文件通过vpath查找
$(OBJ_PATH)/%.o: %.cpp
	@echo "Compiling C++ file: $<"
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@

# 链接生成可执行文件
$(EXE): $(OBJ)
	@echo "Linking objects to create target: $@"
	$(CXX) $^ $(LDLIBS) -o $@

# 创建输出目录(使用order-only依赖,确保目录仅在需要时创建)
$(OBJ_PATH) $(BIN_PATH):
	mkdir -p $@

# 让可执行文件依赖输出目录,确保目录先创建
$(EXE): | $(OBJ_PATH) $(BIN_PATH)

# 清理规则
clean:
	$(RM) -r $(OBJ_PATH) $(BIN_PATH)

show:
	@printf "\nPaths: $(OBJ_PATH) $(BIN_PATH)\n"
	@printf "\nSource files:\n$(SRC)"
	@printf "\n\nObject files:\n$(OBJ)"
	@printf "\n\nCompiler:\n$(CC)"
	@printf "\n\nC++ Compiler:\n$(CXX)"
	@printf "\n\nC Flags:\n$(CFLAGS)"
	@printf "\n\nC++ Flags:\n$(CXXFLAGS)"
	@printf "\n\nInclude Flags:\n$(CPPFLAGS)"
	@printf "\n\nLinked Libraries:\n$(LDLIBS)"
	@echo   ""

关键修复说明

  • 修正目标文件路径:通过addprefix为所有目标文件添加OBJ_PATH/前缀,明确目标文件的输出位置。
  • 添加源文件搜索路径:vpath指令告诉make在所有源文件子目录中查找.c/.cpp文件,解决编译规则找不到源文件的问题。
  • 规范目录创建逻辑:使用order-only依赖替代直接执行shell命令,确保目录仅在需要时创建,符合make的依赖管理规范。
  • 添加默认目标:明确all为默认目标,避免make找不到默认构建入口。
  • 处理重复目标:针对24cXX.c和24cXX.cpp的冲突,需手动重命名其中一个源文件,或修改目标文件命名规则(如生成24cXX_c.o和24cXX_cpp.o)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 11:32:06