Makefile自定义函数报错:实现build/test编译不同入口C代码遇阻
Makefile 错误分析与修正方案
错误原因
你遇到的报错源于$(call preprocess,$(RAW_FILES),$(SRC_FILES))这一行的用法错误。当调用自定义preprocess函数时,你直接传入了多个目标文件(RAW_FILES)和多个源文件(SRC_FILES),展开后会生成形如./build/insane.i ./src/main.i: ./src/core/insane.c ./src/main.c的规则。Make会把这一行的目标部分误认为是要执行的命令,而非规则定义,因此抛出“找不到文件或目录”的错误。
修正后的Makefile实现
BINARY=app.bin TEST_BINARY=test.bin CC=clang CFLAGS=-Wall -Wextra -g -O0 DFLAGS=-MP -MD GLOBAL_INCLUDE_DIR=/usr/local/include BUILD_DIR=./build LIB_DIR=./lib INCLUDE_DIR=./include SRC_DIR=./src/core MAIN_DIR=./src # 通用核心源文件(src/core下的所有.c文件) CORE_SRC_FILES=$(shell find $(SRC_DIR) -type f -name *.c) CORE_OBJ_FILES=$(patsubst $(SRC_DIR)/%,$(BUILD_DIR)/%,$(CORE_SRC_FILES:.c=.o)) INCLUDE_FLAGS=-I$(GLOBAL_INCLUDE_DIR) -I$(INCLUDE_DIR) LIB_FLAGS=-L$(LIB_DIR) # build目标:使用main.c作为入口,生成app.bin build: BINARY_ENTRY=$(MAIN_DIR)/main.c build: BINARY_TARGET=$(BINARY) build: build-core $(BINARY_TARGET) # test目标:使用test.c作为入口,生成test.bin test: BINARY_ENTRY=$(MAIN_DIR)/test.c test: BINARY_TARGET=$(TEST_BINARY) test: build-core $(BINARY_TARGET) # 预处理规则:将.c文件转为.i预处理文件 $(BUILD_DIR)/%.i: %.c mkdir -p $(dir $@) $(CC) -E $(INCLUDE_FLAGS) $(CFLAGS) -o $@ $< # 编译规则:将.c文件转为.s汇编文件 $(BUILD_DIR)/%.s: %.c mkdir -p $(dir $@) $(CC) -S $(INCLUDE_FLAGS) $(CFLAGS) -o $@ $< # 汇编规则:将.c文件转为.o目标文件 $(BUILD_DIR)/%.o: %.c mkdir -p $(dir $@) $(CC) -c $(INCLUDE_FLAGS) $(CFLAGS) $(DFLAGS) -o $@ $< # 编译核心代码的伪目标 .PHONY: build-core build-core: $(CORE_OBJ_FILES) # 链接最终二进制文件的规则 $(BINARY_TARGET): $(CORE_OBJ_FILES) $(BUILD_DIR)/$(notdir $(BINARY_ENTRY:.c=.o)) $(CC) -o $@ $^ $(LIB_FLAGS) # 清理构建产物 clean: rm -rf $(BUILD_DIR) $(BINARY) $(TEST_BINARY) # 调试用:打印变量信息 echo: @echo "[CORE_SRC_FILES]: $(CORE_SRC_FILES)" @echo "[CORE_OBJ_FILES]: $(CORE_OBJ_FILES)" @echo "[BUILD_ENTRY]: $(BINARY_ENTRY)"
关键改进点
- 目标特定变量:为
build和test分别定义专属的入口文件和输出二进制名,变量仅在对应目标上下文生效,避免全局变量冲突。 - 模式规则替代自定义函数:用
$(BUILD_DIR)/%.o: %.c这类通用模式规则自动匹配源文件与目标文件,无需手动维护文件列表,减少出错概率。 - 核心代码与入口分离:
src/core下的核心代码单独编译为目标文件,再与入口文件(main.c/test.c)的目标文件链接,避免重复编译核心代码。 - 清晰的依赖链:最终二进制文件明确依赖核心目标文件和入口目标文件,确保所有必要代码被正确包含。
使用说明
make build:编译核心代码+src/main.c,生成app.binmake test:编译核心代码+src/test.c,生成test.binmake clean:清理构建目录和所有二进制产物
内容的提问来源于stack exchange,提问作者HamLibrary
相关产品推荐
相关产品推荐

