如何编写Makefile实现src目录下各cpp文件独立编译输出到Obj目录
规则含义说明
你最开始写的%: %.cpp是Make的静态模式规则,语法为目标列表: 目标匹配模式: 依赖匹配模式:
- 规则作用对象是前面列出的
$(objects)即test、helloworld两个目标 - 模式里的
%是通配符,会匹配目标名中的任意非空字符串(称为「词干」) - 依赖部分的
%.cpp会把匹配到的词干代入,自动找同名的.cpp文件作为依赖
这条规则等价于手动写两条独立规则:
test: test.cpp $(CC) $(CFLAGS) -o $@ $< helloworld: helloworld.cpp $(CC) $(CFLAGS) -o $@ $<
你之前以为会先生成.o文件再链接,是混淆了规则优先级:你手写的静态模式规则优先级高于Make内置的隐式编译规则,因此不会走「cpp→o→可执行文件」的流程,直接把源码编译成最终目标。
之前分目录编译失败的核心原因
你写的参考规则出现乱编译、重复覆盖输出文件的问题,本质是三个低级错误:
- 没有把
all放在Makefile的第一个位置作为默认目标,你写的首个目标是main.exe,如果文件里残留旧规则、或者路径匹配失效,Make会fallback到内置的%.o: %.cpp隐式规则,把当前目录下的.o文件当成构建目标,才会出现所有cpp都编译到同一个helloworld.o的现象 - 规则里生成的是
.o目标文件,和你预期的.out可执行文件后缀不匹配 - 没有提前创建
Obj输出目录,输出路径不存在时会导致规则匹配异常、编译报错
符合需求的可用Makefile实现
对应你的目录结构:
- 源码目录
src/下存放Test.cpp、Helloworld.cpp - 编译输出到
Obj/目录,生成Test.out、Helloworld.out
直接用下面的配置即可:
# 基础编译配置 CC := g++ CFLAGS := -g -Wall SRC_DIR := src OBJ_DIR := Obj # 自动扫描源码,生成对应目标文件列表 SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp) TARGETS := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.out,$(SRC_FILES)) # 声明伪目标,避免和同名文件冲突 .PHONY: all clean # 默认目标:编译所有可执行文件 all: $(TARGETS) # 静态模式规则:逐个编译源码到输出目录 $(TARGETS): $(OBJ_DIR)/%.out: $(SRC_DIR)/%.cpp | $(OBJ_DIR) $(CC) $(CFLAGS) -o $@ $< # 顺序依赖:编译前自动创建输出目录,不会因目录时间戳触发重复编译 $(OBJ_DIR): mkdir -p $@ # 清理编译产物 clean: rm -rf $(OBJ_DIR)
直接在Makefile所在目录执行make,就会自动创建Obj目录,将两个源码文件分别编译为对应名称的.out可执行文件存入,不会出现规则串扰、重复编译的问题。
内容的提问来源于stack exchange,提问作者Nekromencer
相关产品推荐
相关产品推荐

