# SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2026 Richard Qin # # LumeOS Kernel Makefile (Non-Recursive) # # Usage: # make - Build kernel ELF # make run - Run in QEMU # make debug - Run in QEMU with GDB server # make clean - Clean build artifacts # make fmt - Format all source files # make disasm - Generate disassembly listing # # Reference: docs/specs/00_conventions.md §7 # ============================================================ # Build Configuration # ============================================================ BUILD := build # Load Kconfig infrastructure (reads .config, sets KCPPFLAGS) include scripts/Kconfig.mk ARCH ?= $(CONFIG_ARCH) VMLINUX_PRE := $(BUILD)/kernel.pre.elf VMLINUX := $(BUILD)/kernel.elf VMLINUX_RAW := $(BUILD)/vmlume.raw.bin IMAGE := $(BUILD)/vmlume.bin RELOC_BIN := $(BUILD)/reloc.bin RELOC_OBJ := $(BUILD)/reloc.o LDS_SRC := arch/$(ARCH)/kernel/lumeos.lds.S LINKER_SCRIPT := $(BUILD)/lumeos.lds PYTHON ?= python3 # ============================================================ # Toolchain Detection # ============================================================ ifndef TOOLCHAIN_PREFIX ifeq ($(ARCH),riscv) TOOLCHAIN_PREFIX := $(shell \ if command -v riscv64-linux-gnu-gcc >/dev/null 2>&1; then \ echo riscv64-linux-gnu-; \ elif command -v riscv64-unknown-linux-gnu-gcc >/dev/null 2>&1; then \ echo riscv64-unknown-linux-gnu-; \ elif command -v riscv64-unknown-elf-gcc >/dev/null 2>&1; then \ echo riscv64-unknown-elf-; \ else \ echo riscv64-linux-gnu-; \ fi) else ifeq ($(ARCH),aarch64) TOOLCHAIN_PREFIX := aarch64-linux-gnu- else ifeq ($(ARCH),x86_64) TOOLCHAIN_PREFIX := x86_64-linux-gnu- endif endif CC := $(TOOLCHAIN_PREFIX)gcc CXX := $(TOOLCHAIN_PREFIX)g++ LD := $(TOOLCHAIN_PREFIX)ld OBJCOPY := $(TOOLCHAIN_PREFIX)objcopy OBJDUMP := $(TOOLCHAIN_PREFIX)objdump # Objcopy output formats for binary-to-ELF relocation blob OBJCOPY_ELF_riscv := elf64-littleriscv OBJCOPY_ELF_aarch64 := elf64-littleaarch64 OBJCOPY_ELF_x86_64 := elf64-x86-64 OBJCOPY_ELF := $(OBJCOPY_ELF_$(ARCH)) OBJCOPY_BINARCH_riscv := riscv OBJCOPY_BINARCH_aarch64 := aarch64 OBJCOPY_BINARCH_x86_64 := i386:x86-64 OBJCOPY_BINARCH := $(OBJCOPY_BINARCH_$(ARCH)) # Common flags (base, before module includes) WARNINGS := -Wall -Wextra -Wno-unused-parameter INCLUDES := -Iinclude -I. # ============================================================ # Source Collection (Non-Recursive Module Fragments) # Module .mk files may append to SRCS_CC, SRCS_S, INCLUDES # ============================================================ SRCS_CC := SRCS_C := SRCS_S := SRCS_s := -include arch/$(ARCH)/module.mk include kernel/module.mk include mm/module.mk # include fs/module.mk # Phase 3 include drivers/module.mk include fdt/module.mk include lib/module.mk include test/module.mk # Compiler flags (defined AFTER includes so INCLUDES is complete) CFLAGS := $(WARNINGS) -O2 -g \ -ffreestanding -nostdlib \ -mcmodel=medany \ -MMD -MP \ $(KCPPFLAGS) \ $(INCLUDES) \ -I$(BUILD)/generated # C flags for musl libc sources: add libc-shim headers first CFLAGS_LIBC := $(CFLAGS) -Iinclude/libc-shim \ -Wno-parentheses -Wno-sign-compare CXXFLAGS := $(CFLAGS) \ -std=c++17 \ -fno-exceptions -fno-rtti -fno-use-cxa-atexit \ -fno-threadsafe-statics ASFLAGS := $(CFLAGS) LDFLAGS := -nostdlib -static --emit-relocs # ============================================================ # Object File Computation # ============================================================ OBJS := $(patsubst %.cc,$(BUILD)/%.o,$(SRCS_CC)) \ $(patsubst %.c,$(BUILD)/%.o,$(SRCS_C)) \ $(patsubst %.S,$(BUILD)/%.o,$(SRCS_S)) \ $(patsubst %.s,$(BUILD)/%.o,$(SRCS_s)) DEPS := $(OBJS:.o=.d) # ============================================================ # Build Rules # ============================================================ .PHONY: all clean run debug fmt disasm defconfig savedefconfig showconfig all: $(IMAGE) # Generate autoconf.h before any compilation $(AUTOCONF_H): scripts/Kconfig.mk $(wildcard .config) $(generate-autoconf) # All objects depend on autoconf.h $(OBJS): $(AUTOCONF_H) # Preprocess linker script template (.lds.S → .lds) $(LINKER_SCRIPT): $(LDS_SRC) include/lume/lumeos.lds.h @echo " LDS $@" @mkdir -p $(dir $@) @$(CC) -E -P -x c $(INCLUDES) $< -o $@ # Link kernel ELF $(VMLINUX_PRE): $(OBJS) $(LINKER_SCRIPT) @echo " LD $@" @mkdir -p $(dir $@) @$(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) -o $@ $(OBJS) @$(TOOLCHAIN_PREFIX)size $@ $(RELOC_BIN): $(VMLINUX_PRE) scripts/gen_reloc.py @echo " RELOC $@" @mkdir -p $(dir $@) @$(PYTHON) scripts/gen_reloc.py --elf $< --out $@ $(RELOC_OBJ): $(RELOC_BIN) @echo " OBJCOPY $@" @$(OBJCOPY) -I binary -O $(OBJCOPY_ELF) -B $(OBJCOPY_BINARCH) \ --rename-section .data=.lume.reloc,alloc,load,readonly,data,contents \ $< $@ $(VMLINUX): $(OBJS) $(RELOC_OBJ) $(LINKER_SCRIPT) @echo " LD $@" @mkdir -p $(dir $@) @$(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) -o $@ $(OBJS) $(RELOC_OBJ) @$(TOOLCHAIN_PREFIX)size $@ # Generate flat binary for QEMU loading $(VMLINUX_RAW): $(VMLINUX) @echo " OBJCOPY $@" @$(OBJCOPY) -O binary $< $@ ifeq ($(CONFIG_KERNEL_COMPRESSED),y) $(IMAGE): $(VMLINUX_RAW) $(VMLINUX) scripts/pack_image.py @echo " PACK $@" @$(PYTHON) scripts/pack_image.py --elf $(VMLINUX) --input $< --output $@ --compress lz4 else $(IMAGE): $(VMLINUX_RAW) $(VMLINUX) scripts/pack_image.py @echo " PACK $@" @$(PYTHON) scripts/pack_image.py --elf $(VMLINUX) --input $< --output $@ --compress none endif # Compile C++ sources $(BUILD)/%.o: %.cc @echo " CXX $<" @mkdir -p $(dir $@) @$(CXX) $(CXXFLAGS) -c $< -o $@ # Compile C sources (musl libc) $(BUILD)/%.o: %.c @echo " CC $<" @mkdir -p $(dir $@) @$(CC) $(CFLAGS_LIBC) -c $< -o $@ # Assemble (preprocessed .S) $(BUILD)/%.o: %.S @echo " AS $<" @mkdir -p $(dir $@) @$(CC) $(ASFLAGS) -c $< -o $@ # Assemble (raw .s, no preprocessing) $(BUILD)/%.o: %.s @echo " AS $<" @mkdir -p $(dir $@) @$(CC) $(ASFLAGS) -c $< -o $@ # Auto-dependency tracking -include $(DEPS) # ============================================================ # Run & Debug # ============================================================ ifeq ($(ARCH),riscv) QEMU := qemu-system-riscv64 QEMU_MACHINE := -machine virt -m 128M -nographic QEMU_BIOS := -bios default else ifeq ($(ARCH),aarch64) QEMU := qemu-system-aarch64 QEMU_MACHINE := -machine virt -cpu cortex-a53 -m 128M -nographic QEMU_BIOS := else ifeq ($(ARCH),x86_64) QEMU := qemu-system-x86_64 QEMU_MACHINE := -m 128M -nographic QEMU_BIOS := endif run: $(IMAGE) @echo " QEMU Running..." $(QEMU) $(QEMU_MACHINE) $(QEMU_BIOS) -kernel $(IMAGE) debug: $(IMAGE) @echo " QEMU Waiting for GDB on :1234..." $(QEMU) $(QEMU_MACHINE) $(QEMU_BIOS) -kernel $(IMAGE) -s -S # ============================================================ # Utilities # ============================================================ clean: rm -rf $(BUILD) disasm: $(VMLINUX) @echo " OBJDUMP $<" @$(OBJDUMP) -d -S $(VMLINUX) > $(VMLINUX).asm @echo " Written to $(VMLINUX).asm" fmt: @echo " FMT Formatting source files..." @find . -name '*.cc' -o -name '*.h' | xargs clang-format -i 2>/dev/null || true lint: @echo " LINT Generating compile_commands.json via bear..." @bear -- $(MAKE) all @echo " LINT Running clang-tidy on C++ sources..." @clang-tidy -p . $(SRCS_CC) || true # Print build info (for debugging Makefile issues) info: @echo "TOOLCHAIN_PREFIX = $(TOOLCHAIN_PREFIX)" @echo "SRCS_CC = $(SRCS_CC)" @echo "SRCS_S = $(SRCS_S)" @echo "OBJS = $(OBJS)" @echo "KCPPFLAGS = $(KCPPFLAGS)"