feat(forge): unify build system, deprecate shell scripts (Phase 15)

This commit is contained in:
Markus Maiwald 2026-01-01 20:23:54 +01:00
parent 9733300d3d
commit 3a907439fe
1 changed files with 0 additions and 738 deletions

738
build.sh
View File

@ -1,738 +0,0 @@
#!/usr/bin/env bash
# Markus Maiwald (Architect) | Voxis Forge (AI)
set -e
# Nexus Rumpk Build Script v0.4
# "Split Brain" Networking Edition
RUMPK_DIR=$(pwd)
BUILD_DIR="$RUMPK_DIR/build"
mkdir -p "$BUILD_DIR"
export ZIG_GLOBAL_CACHE_DIR="$BUILD_DIR/.zig-cache"
export ZIG_LOCAL_CACHE_DIR="$BUILD_DIR/.zig-cache-local"
ARCH=${1:-riscv64}
case $ARCH in
riscv64)
ZIG_TARGET="riscv64-freestanding-none"
ZIG_OBJ_FLAGS="-mcpu=sifive_u54 -mcmodel=medany"
ARCH_FLAGS="-mcpu=sifive_u54 -mabi=lp64d -mcmodel=medany -ffunction-sections -fdata-sections"
NIM_CPU="riscv64"
NIM_DEFINE="riscv64"
ENTRY_FILE="riscv"
;;
x86_64)
ZIG_TARGET="x86_64-freestanding-none"
ARCH_FLAGS="-mno-red-zone"
NIM_CPU="amd64"
NIM_DEFINE="x86_64"
ENTRY_FILE="x86_64"
;;
aarch64)
ZIG_TARGET="aarch64-freestanding-none"
ARCH_FLAGS=""
NIM_CPU="arm64"
NIM_DEFINE="aarch64"
ENTRY_FILE="aarch64"
;;
*)
echo "Unsupported architecture: $ARCH"
exit 1
;;
esac
echo "╔═══════════════════════════════════════╗"
echo "║ RUMPK MULTI-ARCH BUILD v0.4 ║"
echo "║ Architecture: $ARCH "
echo "╚═══════════════════════════════════════╝"
# =========================================================
# Step 1: Compile Zig L0 (HAL + libc stubs)
# =========================================================
echo "[1/8] Compiling Zig L0 (HAL + libc stubs)..."
zig build-obj \
-target $ZIG_TARGET \
$ZIG_OBJ_FLAGS \
-O ReleaseFast \
"$RUMPK_DIR/hal/entry_$ENTRY_FILE.zig" \
--name hal
mv hal.o "$BUILD_DIR/hal.o"
echo "$BUILD_DIR/hal.o"
zig build-obj \
-target $ZIG_TARGET \
$ZIG_OBJ_FLAGS \
-O ReleaseFast \
"$RUMPK_DIR/hal/stubs.zig" \
--name stubs
mv stubs.o "$BUILD_DIR/stubs.o"
echo "$BUILD_DIR/stubs.o"
zig build-obj \
-target $ZIG_TARGET \
$ZIG_OBJ_FLAGS \
-O ReleaseFast \
"$RUMPK_DIR/hal/channel.zig" \
--name channel
mv channel.o "$BUILD_DIR/channel.o"
echo "$BUILD_DIR/channel.o"
# Compile NexShell NPL (Immune System Voice)
echo "[1.1/8] Compiling NexShell NPL..."
zig build-obj \
-target $ZIG_TARGET \
$ZIG_OBJ_FLAGS \
-O ReleaseFast \
"$RUMPK_DIR/src/npl/system/nexshell.zig" \
--name nexshell
mv nexshell.o "$BUILD_DIR/nexshell.o"
echo "$BUILD_DIR/nexshell.o"
# Compile UI (Zicroui)
echo "[1.2/8] Compiling UI (Zicroui)..."
zig build-obj \
-target $ZIG_TARGET \
$ZIG_OBJ_FLAGS \
-O ReleaseFast \
-I"$RUMPK_DIR/libs/microui" \
"$RUMPK_DIR/hal/ui.zig" \
--name ui
mv ui.o "$BUILD_DIR/ui.o"
echo "$BUILD_DIR/ui.o"
# Compile GPU Driver (Retina)
echo "[1.3/8] Compiling GPU Driver (VirtIO-GPU)..."
zig build-obj \
-target $ZIG_TARGET \
$ZIG_OBJ_FLAGS \
-O ReleaseFast \
"$RUMPK_DIR/hal/gpu.zig" \
--name gpu
mv gpu.o "$BUILD_DIR/gpu.o"
echo "$BUILD_DIR/gpu.o"
# Compile Matrix Protocol (Rainmaker)
echo "[1.4/8] Compiling Matrix Protocol..."
zig build-obj \
-target $ZIG_TARGET \
$ZIG_OBJ_FLAGS \
-O ReleaseFast \
"$RUMPK_DIR/hal/matrix.zig" \
--name matrix
mv matrix.o "$BUILD_DIR/matrix.o"
echo "$BUILD_DIR/matrix.o"
# =========================================================
# Step 2: Compile context switch assembly
# =========================================================
echo "[2/8] Compiling context switch ($ARCH)..."
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-c "$RUMPK_DIR/hal/arch/$ARCH/switch.S" \
-o "$BUILD_DIR/switch.o"
echo "$BUILD_DIR/switch.o"
# =========================================================
# Step 2.1: Compile Monocypher
# =========================================================
echo "[2.1/8] Compiling Monocypher..."
zig cc \
-target $ZIG_TARGET \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-O3 \
-c "$RUMPK_DIR/hal/crypto/monocypher.c" \
-o "$BUILD_DIR/monocypher.o"
echo "$BUILD_DIR/monocypher.o"
# =========================================================
# Step 2.1b: Compile Microui
# =========================================================
echo "[2.1b/8] Compiling Microui..."
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-O3 \
-I"$RUMPK_DIR/libs/microui/include" \
-c "$RUMPK_DIR/libs/microui/microui.c" \
-o "$BUILD_DIR/microui.o"
echo "$BUILD_DIR/microui.o"
# =========================================================
# Step 2.2: Compile LwIP (Kernel Stack)
# =========================================================
# echo "[2.2/8] Compiling LwIP (Kernel)..."
# LWIP_CORE_FILES=(
# "src/core/init.c"
# "src/core/def.c"
# "src/core/dns.c"
# "src/core/inet_chksum.c"
# "src/core/ip.c"
# "src/core/mem.c"
# "src/core/memp.c"
# "src/core/netif.c"
# "src/core/pbuf.c"
# "src/core/raw.c"
# "src/core/stats.c"
# "src/core/sys.c"
# "src/core/tcp.c"
# "src/core/tcp_in.c"
# "src/core/tcp_out.c"
# "src/core/timeouts.c"
# "src/core/udp.c"
# "src/core/ipv4/autoip.c"
# "src/core/ipv4/dhcp.c"
# "src/core/ipv4/etharp.c"
# "src/core/ipv4/icmp.c"
# "src/core/ipv4/igmp.c"
# "src/core/ipv4/ip4.c"
# "src/core/ipv4/ip4_addr.c"
# "src/core/ipv4/ip4_frag.c"
# "src/netif/ethernet.c"
# )
#
# for cfile in "${LWIP_CORE_FILES[@]}"; do
# cfile_path="$RUMPK_DIR/vendor/lwip/$cfile"
# objname=$(basename "$cfile" .c)
# zig cc \
# -target $ZIG_TARGET \
# $ARCH_FLAGS \
# -ffreestanding \
# -fno-stack-protector \
# -fno-builtin \
# -O2 \
# -I"$RUMPK_DIR/core/include" \
# -I"$RUMPK_DIR/core/net" \
# -I"$RUMPK_DIR/vendor/lwip/src/include" \
# -c "$cfile_path" \
# -o "$BUILD_DIR/lwip_kernel_$objname.o"
# done
# =========================================================
# Step 2.3: Compile LwIP (Membrane Stack)
# =========================================================
echo "[2.3/8] Skipping LwIP (Removed)..."
# LwIP was removed from the build
LWIP_MEMBRANE_OBJS=""
# Compile sys_arch.c (LwIP Platform Abstraction)
echo "[2.4/8] Compiling LwIP Platform Layer (sys_arch.c)..."
# zig cc \
# -target $ZIG_TARGET \
# $ARCH_FLAGS \
# -ffreestanding \
# -fno-stack-protector \
# -fno-builtin \
# -O2 \
# -I"$RUMPK_DIR/core/include" \
# -I"$RUMPK_DIR/core/net" \
# -I"$RUMPK_DIR/vendor/lwip/src/include" \
# -c "$RUMPK_DIR/core/net/sys_arch.c" \
# -o "$BUILD_DIR/sys_arch.o"
#
# echo " → LwIP objects compiled."
# =========================================================
# Step 3: Compile Nim L1 (Kernel + Fibers)
# =========================================================
echo "[3/8] Compiling Nim L1 (Kernel + Fibers)..."
mkdir -p "$BUILD_DIR/nimcache"
nim c \
--cpu:$NIM_CPU \
--os:any \
--mm:arc \
--noMain:on \
--cc:clang \
--passC:"-target ${ZIG_TARGET/-freestanding-none/-unknown-none} -ffreestanding -fno-stack-protector -fno-builtin $ARCH_FLAGS -I$RUMPK_DIR/core/include -O3 -flto" \
--define:useMalloc \
--define:nimNoLibc \
--define:noSignalHandler \
--define:$NIM_DEFINE \
-d:danger \
--opt:speed \
--nimcache:"$BUILD_DIR/nimcache" \
--path:"$RUMPK_DIR/core" \
-c \
"$RUMPK_DIR/core/kernel.nim"
# =========================================================
# Step 4: Compile Nim C files
# =========================================================
echo "[4/8] Compiling Nim C files..."
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-O2 \
-I"$RUMPK_DIR/core/include" \
-c "$RUMPK_DIR/core/cstubs.c" \
-o "$BUILD_DIR/cstubs.o"
echo "$BUILD_DIR/cstubs.o"
NIM_OBJS=""
for cfile in "$BUILD_DIR/nimcache"/*.c; do
ofile="${cfile%.c}.o"
zig cc \
-target $ZIG_TARGET \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-fno-sanitize=all \
$ARCH_FLAGS \
-I"$RUMPK_DIR/core/include" \
-I/usr/lib/nim \
-I"$RUMPK_DIR/core" \
-O3 -flto \
-c "$cfile" \
-o "$ofile"
NIM_OBJS="$NIM_OBJS $ofile"
done
echo "$BUILD_DIR/nimcache/*.o"
# =========================================================
# Step 4.1: Compile Overrides (Math/Atomics Stubs)
# =========================================================
echo "[4.1/8] Compiling Sovereign Overrides..."
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-O2 \
-I"$RUMPK_DIR/core/include" \
-c "$RUMPK_DIR/core/overrides.c" \
-o "$BUILD_DIR/overrides.o"
echo "$BUILD_DIR/overrides.o"
# =========================================================
# Step 5: Compile Membrane Library (libnexus.a)
# =========================================================
echo "[5/8] Compiling Membrane Library (libnexus.a)..."
mkdir -p "$BUILD_DIR/membrane_nimcache"
# Compile clib.c (The Mini-Libc)
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-O2 \
-I"$RUMPK_DIR/core/include" \
-c "$RUMPK_DIR/libs/membrane/clib.c" \
-o "$BUILD_DIR/clib.o"
# Compile sys_arch.c (Membrane LwIP Platform Layer)
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-O2 \
-I"$RUMPK_DIR/core/include" \
-I"$RUMPK_DIR/libs/membrane/include" \
-I"$RUMPK_DIR/vendor/lwip/src/include" \
-c "$RUMPK_DIR/libs/membrane/sys_arch.c" \
-o "$BUILD_DIR/membrane_sys_arch.o"
nim c \
--cpu:$NIM_CPU \
--os:any \
-d:is_membrane \
-d:danger \
--opt:speed \
-d:useMalloc \
-d:nimNoLibc \
-d:noSignalHandler \
--gc:arc \
--panics:on \
--app:staticlib \
--nimMainPrefix:Membrane \
--hint:Conf:off \
--hint:OSLib:off \
--nimcache:"$BUILD_DIR/membrane_nimcache" \
--path:"$RUMPK_DIR/libs/membrane" \
--path:"$RUMPK_DIR/core" \
-c \
"$RUMPK_DIR/libs/membrane/libc.nim"
MEMBRANE_NIM_OBJS=""
for cfile in "$BUILD_DIR/membrane_nimcache"/*.c; do
ofile="${cfile%.c}.o"
zig cc \
-target $ZIG_TARGET \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-fno-sanitize=all \
$ARCH_FLAGS \
-I"$RUMPK_DIR/core/include" \
-I/usr/lib/nim \
-I"$RUMPK_DIR/core" \
-I"$RUMPK_DIR/libs/membrane" \
-I"$RUMPK_DIR/libs/membrane/include" \
-I"$RUMPK_DIR/vendor/lwip/src/include" \
-O3 -flto \
-c "$cfile" \
-o "$ofile"
MEMBRANE_NIM_OBJS="$MEMBRANE_NIM_OBJS $ofile"
done
# =========================================================
# Step 5.1: [MOVED] NipBox compilation happens AFTER libnexus.a
# =========================================================
# NipBox requires libnexus.a to link, so it's compiled at Step 5.6
echo "[5.1/8] Skipping Subject (NipBox will be compiled after Membrane)..."
# =========================================================
# Step 5.5: Patch Atomic References & Nuke Cache (GLOBAL)
# =========================================================
# We must do this BEFORE creating archives or linking anything.
# This ensures broken libcompiler_rt refs are removed from ALL objects.
echo "[5.5/8] Patching Atomic References & Nuking Cache..."
find "$BUILD_DIR" -name "*.o" | while read obj; do
zig objcopy --redefine-syms="$RUMPK_DIR/core/re-symbol.txt" "$obj" "$obj" 2>/dev/null || true
# Remove auto-linking sections
zig objcopy \
--remove-section .linker-options \
--remove-section .comment \
--remove-section .deplibs \
--remove-section .llvm_addrsig \
--remove-section .dependent-lib \
"$obj" "$obj" 2>/dev/null || true
done
echo " → SWAPPING libcompiler_rt.a with dummy archive (GLOB)..."
echo "" > "$BUILD_DIR/dummy.c"
zig cc -target $ZIG_TARGET -c "$BUILD_DIR/dummy.c" -o "$BUILD_DIR/dummy.o" $ARCH_FLAGS
for lib in "$BUILD_DIR"/.zig-cache/o/*/libcompiler_rt.a; do
if [ -f "$lib" ]; then
echo " Replacing $lib"
rm -f "$lib"
zig ar rc "$lib" "$BUILD_DIR/dummy.o"
fi
done
# =========================================================
# Step 5b: Create Membrane Archive
# =========================================================
# Note: We manually include ion_switch.o from the KERNEL nimcache if needed,
# but it should be in membrane_nimcache too because libc.nim imports it.
# Let's verify if ion_switch.o exists in membrane_nimcache.
ION_SWITCH_OBJ=$(ls "$BUILD_DIR/membrane_nimcache"/*ion_switch*o 2>/dev/null || echo "")
zig ar rc "$BUILD_DIR/libnexus.a" \
$MEMBRANE_NIM_OBJS \
$LWIP_MEMBRANE_OBJS \
"$BUILD_DIR/clib.o" \
"$BUILD_DIR/membrane_sys_arch.o" \
"$BUILD_DIR/switch.o"
echo "$BUILD_DIR/libnexus.a"
# =========================================================
# Step 5.6: Compile NipBox (The Sovereign Userland)
# =========================================================
echo "[5.6/8] Compiling NipBox (Sovereign Userland)..."
# Stage 1: Let Nim generate C code only (no linking)
nim c \
--cpu:$NIM_CPU \
--os:any \
-d:danger \
--opt:size \
-d:useMalloc \
-d:nimNoLibc \
-d:noSignalHandler \
--mm:arc \
--checks:off \
--panics:on \
--noMain:off \
--hint:Conf:off \
--hint:OSLib:off \
--nimcache:"$BUILD_DIR/nipbox_nimcache" \
--path:"$RUMPK_DIR/libs/membrane" \
--path:"$RUMPK_DIR/core" \
--compileOnly \
"$RUMPK_DIR/npl/nipbox/nipbox.nim"
# Stage 2: Compile all C files with zig cc
echo "[5.6.1/8] Compiling NipBox C files with zig cc..."
NIPBOX_OBJS=""
find "$BUILD_DIR/nipbox_nimcache" -name "*.c" | while read cfile; do
ofile="${cfile%.c}.o"
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-Os \
-ffunction-sections \
-fdata-sections \
-I/usr/lib/nim \
-I"$RUMPK_DIR/core/include" \
-c "$cfile" \
-o "$ofile"
done
# Collect all object files
NIPBOX_OBJS=$(find "$BUILD_DIR/nipbox_nimcache" -name "*.o" | tr '\n' ' ')
# Stage 2.5: Compile libc_shim.zig (Universal Adapter)
echo "[5.6.1b/8] Compiling libc_shim.zig..."
zig build-obj \
-target $ZIG_TARGET \
$ZIG_OBJ_FLAGS \
-O ReleaseSmall \
"$RUMPK_DIR/libs/membrane/libc_shim.zig" \
--name libc_shim
mv libc_shim.o "$BUILD_DIR/libc_shim.o"
# Stage 2.6: Compile subject_entry.S
echo "[5.6.1c/8] Compiling subject_entry.S..."
zig cc -target $ZIG_TARGET -ffreestanding -c "$RUMPK_DIR/apps/subject_entry.S" -o "$BUILD_DIR/subject_entry.o"
# Stage 3: Link with zig cc
echo "[5.6.2/8] Linking NipBox binary..."
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-fno-stack-protector \
-nostdlib \
-static \
-Wl,--gc-sections \
-T "$RUMPK_DIR/apps/linker_user.ld" \
"$BUILD_DIR/subject_entry.o" \
"$BUILD_DIR/stubs.o" \
$NIPBOX_OBJS \
"$BUILD_DIR/libc_shim.o" \
-L"$BUILD_DIR" \
-lnexus \
-o "$BUILD_DIR/nipbox"
mkdir -p "$RUMPK_DIR/rootfs/bin"
cp "$BUILD_DIR/nipbox" "$RUMPK_DIR/rootfs/bin/nipbox"
echo " → rootfs/bin/nipbox"
# Convert NipBox binary to object file for embedding
echo "[5.6.3/8] Embedding NipBox as Subject..."
llvm-objcopy -O binary "$BUILD_DIR/nipbox" "$BUILD_DIR/nipbox.bin"
# Generate assembly wrapper for safe embedding
cat <<EOF > "$BUILD_DIR/subject_wrapper.S"
.section .rodata
.global _subject_start
.global _subject_end
_subject_start:
.incbin "$BUILD_DIR/nipbox.bin"
_subject_end:
EOF
# Compile wrapper to object file
zig cc \
-target $ZIG_TARGET \
-c "$BUILD_DIR/subject_wrapper.S" \
-o "$BUILD_DIR/subject_zig.o"
echo "$BUILD_DIR/nipbox ($(stat -c%s "$BUILD_DIR/nipbox" 2>/dev/null || echo "unknown") bytes)"
echo "$BUILD_DIR/subject_zig.o (embedded)"
# =========================================================
# Step 5.7: Compile Hello Alien (Test Binary)
# =========================================================
echo "[5.7/8] Compiling Hello Alien..."
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-fno-stack-protector \
-fno-builtin \
-Os \
-I"$RUMPK_DIR/rootfs/src" \
-I"$RUMPK_DIR/core/include" \
-c "$RUMPK_DIR/rootfs/src/hello.c" \
-o "$BUILD_DIR/hello.o"
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-fno-stack-protector \
-nostdlib \
-static \
-Wl,--gc-sections \
-T "$RUMPK_DIR/apps/linker_user.ld" \
"$BUILD_DIR/subject_entry.o" \
"$BUILD_DIR/hello.o" \
"$BUILD_DIR/libc_shim.o" \
-L"$BUILD_DIR" \
-lnexus \
-o "$RUMPK_DIR/rootfs/bin/hello"
echo " → rootfs/bin/hello"
# Copy nipbox to rootfs/bin for TarFS loading
mkdir -p "$RUMPK_DIR/rootfs/bin"
cp "$BUILD_DIR/nipbox" "$RUMPK_DIR/rootfs/bin/nipbox"
# =========================================================
# Step 6: Final Kernel Assembly
# =========================================================
echo "[6/8] Linking Subject Zero (Canary)..."
# Note: subject_zero.o and libnexus.a are already compiled and patched.
# =========================================================
# Step 6: Link Subject Zig
# =========================================================
echo "[6/8] Linking Subject Zig..."
zig cc \
-target $ZIG_TARGET \
-nostdlib \
-T "$RUMPK_DIR/apps/linker_user.ld" \
"$BUILD_DIR/subject_zig.o" \
"$BUILD_DIR/libnexus.a" \
-o "$BUILD_DIR/subject.elf" \
-lgcc
echo "$BUILD_DIR/subject.elf"
zig objcopy -O binary "$BUILD_DIR/subject.elf" "$BUILD_DIR/subject.bin"
echo "$BUILD_DIR/subject.bin"
# =========================================================
# Step 7: Compile Loader (After Subject)
# =========================================================
echo "[7/8] Compiling Loader (with Embedded Subject)..."
# Copy nipbox.bin to core/ so loader.zig can embed it (replacing stale subject.bin)
cp "$BUILD_DIR/nipbox.bin" "$RUMPK_DIR/core/subject.bin"
zig build-obj \
-target $ZIG_TARGET \
$ZIG_OBJ_FLAGS \
-O ReleaseFast \
"$RUMPK_DIR/core/loader.zig" \
--name loader
mv loader.o "$BUILD_DIR/loader.o"
echo "$BUILD_DIR/loader.o"
# Clean up temp file
rm "$RUMPK_DIR/core/subject.bin"
# Patch Loader Object specifically
echo " → Patching Loader Object..."
obj="$BUILD_DIR/loader.o"
zig objcopy --redefine-syms="$RUMPK_DIR/core/re-symbol.txt" "$obj" "$obj" 2>/dev/null || true
zig objcopy \
--remove-section .linker-options \
--remove-section .comment \
--remove-section .deplibs \
--remove-section .llvm_addrsig \
--remove-section .dependent-lib \
"$obj" "$obj" 2>/dev/null || true
# =========================================================
# Step 7.5: Package RootFS (Sovereign VFS)
# =========================================================
echo "[7.5/8] Packaging RootFS (InitRD)..."
# tar --format=ustar -cf "$BUILD_DIR/initrd.tar" -C "$RUMPK_DIR/rootfs" . 2>/dev/null || touch "$BUILD_DIR/initrd.tar"
echo " → Invoking Nexus Forge..."
pushd ../.. > /dev/null
./nexus build
popd > /dev/null
# Generate assembly wrapper for safe embedding
cat <<EOF > "$BUILD_DIR/initrd_wrapper.S"
.section .rodata
.balign 512
.global _initrd_start
.global _initrd_end
_initrd_start:
.incbin "$BUILD_DIR/initrd.tar"
_initrd_end:
EOF
zig cc \
-target $ZIG_TARGET \
$ARCH_FLAGS \
-ffreestanding \
-c "$BUILD_DIR/initrd_wrapper.S" \
-o "$BUILD_DIR/initrd.o"
echo "$BUILD_DIR/initrd.o ($(stat -c%s "$BUILD_DIR/initrd.o" 2>/dev/null || echo "unknown") bytes)"
# =========================================================
# Step 8: Link Kernel (Direct LLD Bypass)
# =========================================================
echo "[8/8] Linking Kernel ($ARCH) using LLD..."
# Check if ld.lld is available, otherwise assume zig cc wrapper but we try direct first
LINKER="ld.lld"
EMULATION=""
if [ "$ARCH" = "riscv64" ]; then
EMULATION="-m elf64lriscv"
elif [ "$ARCH" = "x86_64" ]; then
EMULATION="-m elf_x86_64"
elif [ "$ARCH" = "aarch64" ]; then
EMULATION="-m aarch64elf"
fi
$LINKER \
-t \
$EMULATION \
--gc-sections \
-T "$RUMPK_DIR/hal/arch/$ARCH/linker.ld" \
"$BUILD_DIR/hal.o" \
"$BUILD_DIR/stubs.o" \
"$BUILD_DIR/channel.o" \
"$BUILD_DIR/switch.o" \
"$BUILD_DIR/monocypher.o" \
"$BUILD_DIR/cstubs.o" \
"$BUILD_DIR/overrides.o" \
"$BUILD_DIR/loader.o" \
"$BUILD_DIR/nexshell.o" \
"$BUILD_DIR/ui.o" \
"$BUILD_DIR/gpu.o" \
"$BUILD_DIR/matrix.o" \
"$BUILD_DIR/initrd.o" \
"$BUILD_DIR/microui.o" \
$NIM_OBJS \
-o "$BUILD_DIR/rumpk-$ARCH.elf"
echo "$BUILD_DIR/rumpk-$ARCH.elf"
echo ""
echo "✅ Build complete for $ARCH!"
echo "Run with:"
echo " qemu-system-riscv64 -M virt -nographic -kernel $BUILD_DIR/rumpk-riscv64.elf -netdev user,id=n0 -device virtio-net-pci,netdev=n0,disable-modern=on"
echo ""