#!/bin/bash
# Runs INSIDE the kernel builder container (guest/kernel/Dockerfile); started by
# scripts/build-guest.sh kernel, which unpacks a tar with
#   linux-$LINUX_VERSION.tar.xz  kernel/{base,patches,xvm.config,xvm-debug.config,kbuild.sh}
# into /in first. Writes a tar of the outputs on stdout; everything else goes to stderr.
# The tree lives in the container's own filesystem (/src): the host's target/ is
# case-insensitive APFS/HFS and not shared with the colima VM.
# Env: LINUX_VERSION, SOURCE_DATE_EPOCH, VARIANT=release|debug, MODE=build|config.
set -euo pipefail
exec 3>&1 1>&2
trap 'echo "kbuild.sh: failed at line $LINENO"' ERR

: "${LINUX_VERSION:?}" "${SOURCE_DATE_EPOCH:?}"
VARIANT=${VARIANT:-release}
MODE=${MODE:-build}
mkdir -p /out

tar -xJf "/in/linux-$LINUX_VERSION.tar.xz" -C /
mv "/linux-$LINUX_VERSION" /src
cd /src

for p in /in/kernel/patches/*.patch; do
  echo "patch: ${p##*/}"
  patch -p1 --fuzz=0 --no-backup-if-mismatch < "$p"
done

export ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu-
frags=(/in/kernel/xvm.config)
[ "$VARIANT" = debug ] && frags+=(/in/kernel/xvm-debug.config)
cp /in/kernel/base/config-libkrunfw_riscv64 .config
scripts/kconfig/merge_config.sh -m .config "${frags[@]}" > /out/merge.log
make -s olddefconfig
make -s savedefconfig

# Every line the fragments ask for must survive olddefconfig (libkrunfw lost x86_64's DRM to a
# silently dropped symbol, S1); report the ones that did not.
: > /out/fragment-unmet.txt
for f in "${frags[@]}"; do
  grep -E '^(CONFIG_|# CONFIG_)' "$f" | while IFS= read -r want; do
    sym=$(sed -E 's/^# (CONFIG_[A-Za-z0-9_]+) is not set$/\1/; s/^(CONFIG_[A-Za-z0-9_]+)=.*/\1/' <<<"$want")
    if [[ "$want" == "# "* ]]; then
      # "is not set" is met when the symbol is off or absent.
      if grep -qE "^$sym=" .config; then
        echo "want '$want', got '$(grep -E "^$sym=" .config)'" >> /out/fragment-unmet.txt
      fi
    else
      got=$(grep -E "^($sym=|# $sym is not set)" .config || echo "(absent)")
      if [ "$got" != "$want" ]; then echo "want '$want', got '$got'" >> /out/fragment-unmet.txt; fi
    fi
  done
done
cp .config /out/config
cp defconfig /out/defconfig

if [ "$MODE" = build ]; then
  export KBUILD_BUILD_TIMESTAMP
  KBUILD_BUILD_TIMESTAMP=$(LC_ALL=C date -u -d "@$SOURCE_DATE_EPOCH")
  export KBUILD_BUILD_USER=xvm KBUILD_BUILD_HOST=xvm KBUILD_BUILD_VERSION=1
  t0=$(date +%s)
  make -j"$(nproc)" LOCALVERSION=-xvm KCFLAGS=-ffile-prefix-map=/src=. Image
  echo "build: $(( $(date +%s) - t0 )) s on $(nproc) CPUs"
  cp arch/riscv/boot/Image System.map /out/
  cat include/config/kernel.release > /out/kernel.release
  strings -a vmlinux | grep -m1 '^Linux version ' > /out/linux-version.txt || true
  riscv64-linux-gnu-size vmlinux > /out/size.txt
fi
cp /packages.txt /out/builder-packages.txt
riscv64-linux-gnu-gcc --version | head -1 > /out/toolchain.txt
riscv64-linux-gnu-ld --version | head -1 >> /out/toolchain.txt
tar -cf - -C /out . >&3
