xv6-riscv Makefile 详解与重塑教学
这是一个典型的用于构建嵌入式操作系统(如 xv6)的 Makefile,它处理了:
- 交叉编译
- 依赖管理
- 用户程序构建
- 文件系统打包
- 一键运行等功能
✦ Makefile 总体目标
- 构建内核镜像:
kernel/kernel - 构建文件系统镜像:
fs.img - 提供如
make qemu这样的便捷命令,直接启动 QEMU 模拟器运行系统。
1. 变量定义:方便管理路径和对象文件
# 基本变量
K = kernel
U = user
OBJS = \
$K/entry.o \
$K/start.o \
... \
$K/virtio_disk.o
✅ 说明:
K和U是目录别名,方便后续引用。OBJS是内核需要的所有目标文件列表。写.o文件时要写上路径前缀$K/。
2. 工具链配置:处理交叉编译
ifndef TOOLPREFIX
TOOLPREFIX := $(shell \
if riscv64-unknown-elf-objdump -i 2>&1 | grep 'elf64-big' >/dev/null; then \
echo 'riscv64-unknown-elf-'; \
elif ...; then \
echo '...'; \
else \
echo "*** Error: Can't find toolchain" 1>&2; \
exit 1; \
fi)
endif
CC = $(TOOLPREFIX)gcc
AS = $(TOOLPREFIX)as
LD = $(TOOLPREFIX)ld
OBJCOPY = $(TOOLPREFIX)objcopy
OBJDUMP = $(TOOLPREFIX)objdump
QEMU = qemu-system-riscv64
✅ 说明:
- 自动检测合适的交叉工具链前缀。
- 设置编译器、汇编器、链接器、objcopy 和 objdump。
- 支持用户通过
make TOOLPREFIX=xxx-手动指定。
3. 编译器与链接器参数
CFLAGS = -Wall -Werror -O -fno-omit-frame-pointer -ggdb -gdwarf-2
CFLAGS += -MD -fno-builtin-printf -I.
LDFLAGS = -z max-page-size=4096
✅ 说明:
-nostdlib和-fno-builtin-*是内核开发的必要参数。-MD用于自动生成.d依赖文件。-I.指定头文件搜索路径。
4. 规则定义:Makefile 的核心逻辑
内核构建
$K/kernel: $(OBJS) $K/kernel.ld $U/initcode
$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS)
$(OBJDUMP) -S $K/kernel > $K/kernel.asm
$(OBJDUMP) -t $K/kernel | sed ... > $K/kernel.sym
用户程序构建(模式规则)
ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/umalloc.o
_%: %.o $(ULIB)
$(LD) $(LDFLAGS) -T $U/user.ld -o $@ $^
$(OBJDUMP) -S $@ > $*.asm
$(OBJDUMP) -t $@ | sed ... > $*.sym
UPROGS = \
$U/_cat \
$U/_ls \
$U/_sh \
...
文件系统镜像构建
fs.img: mkfs/mkfs README $(UPROGS)
mkfs/mkfs fs.img README $(UPROGS)
5. 自动依赖管理
-include kernel/*.d user/*.d
✅ 说明:
- 自动包含
.d依赖文件,让头文件变动能触发相应.c文件的重编译。 -include不会因.d文件不存在而报错。
6. 伪目标(Phony Targets)
.PHONY: clean qemu
clean:
rm -f *.o *.d fs.img kernel/kernel user/_* *.sym *.asm
qemu: $K/kernel fs.img
$(QEMU) $(QEMUOPTS)
💡 从零重塑 Makefile 的流程思路
- 定义变量:如
K=kernel,列出OBJS。 - 配置工具链:写死或自动检测
TOOLPREFIX。 - 设定编译参数:
CFLAGS,LDFLAGS。 -
编写构建规则:
- 内核构建:
kernel/kernel - 用户程序模式规则
fs.img构建
- 内核构建:
- 添加自动依赖管理:用
-MD+-include。 - 伪目标:如
clean,qemu,增强易用性。