如何在Makefile中移除目标文件路径的多余中间目录段
问题根因
你当前写的路径替换规则仅针对src/kernel/下的一级C文件做了路径映射,一旦src下存在其他层级的子目录(比如src/cstr/)存放C文件,原有规则无法把多层源路径拍平到build/根目录,就会生成带中间目录段的目标文件。之前用shell find src -name '*.c'没生效,是因为只替换了源文件获取逻辑,没有配套做路径扁平化处理,也没有适配多目录源文件的编译匹配规则。
可直接用的修正方案
核心改动点有三个:
- 用
find递归拉取src下所有层级的汇编、C源文件,不再只匹配单目录 - 配合Makefile内置的
notdir函数去掉源文件的所有目录前缀,直接把目标.o文件统一生成到build/根目录,不存在中间子目录 - 用
vpath配置源文件搜索路径,不用为每个源码子目录单独写编译规则
修正后的完整Makefile如下:
kernel := build/kernel.bin iso := build/os.iso linker_script := src/linker.ld grub_cfg := src/grub.cfg # 递归获取所有汇编、C源文件 assembly_source_files := $(shell find src -type f -name '*.asm') c_source_files := $(shell find src -type f -name '*.c') # 提取纯文件名(剔除所有目录前缀),生成build目录下的平级.o路径 assembly_object_files := $(patsubst %.asm, build/%.o, $(notdir $(assembly_source_files))) c_object_files := $(patsubst %.c, build/%.o, $(notdir $(c_source_files))) # 配置Makefile的源文件搜索范围,覆盖src下所有子目录 vpath %.asm $(shell find src -type d) vpath %.c $(shell find src -type d) .PHONY: all clean run iso all: $(kernel) clean: @rm -rf build run: $(iso) @qemu-system-x86_64 -cdrom $(iso) iso: $(iso) # 预创建build目录,避免编译时找不到路径 $(shell mkdir -p build) $(iso): $(kernel) $(grub_cfg) @mkdir -p build/isofiles/boot/grub @cp $(kernel) build/isofiles/boot/kernel.bin @cp $(grub_cfg) build/isofiles/boot/grub @grub-mkrescue -o $(iso) build/isofiles 2> /dev/null @rm -r build/isofiles $(kernel): $(assembly_object_files) $(c_object_files) $(linker_script) @ld -n -T $(linker_script) -o $(kernel) $(assembly_object_files) $(c_object_files) # 汇编文件编译规则 build/%.o: %.asm @nasm -felf64 $< -o $@ # C文件编译规则 build/%.o: %.c @gcc -c $< -o $@ -std=c11 -ffreestanding -O2 -Wall -Wextra
注意事项
- 如果不同子目录下存在同名的C/汇编文件,路径拍平后会出现目标文件重名覆盖的问题,这种场景要么统一重命名文件,要么保留目标文件的子目录结构避免冲突
- 原脚本里的调试echo语句可以按需删除,不影响构建流程
- clean操作里把
rm -r build改成rm -rf build,避免首次执行clean时因为build目录不存在抛出错误
内容的提问来源于stack exchange,提问作者TRDP
相关产品推荐
相关产品推荐

