Files
xteink-web-emulator/scripts/build-qemu-wasm.sh
T
2026-07-20 16:34:19 -04:00

89 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
SRC="${QEMU_WASM_SRC:-$ROOT/_scratch/qemu-wasm-src}"
OUT="${WASM_OUT:-$ROOT/dist/wasm}"
[[ "$SRC" = /* ]] || SRC="$ROOT/$SRC"
[[ "$OUT" = /* ]] || OUT="$ROOT/$OUT"
TAG="esp-develop-9.2.2-20260417"
COMMIT="40edccac415693c5130f91c01d84176ae6008566"
QEMU_WASM_COMMIT="0ef7b4e2814b231705d8371dd7997f5b72e70baf"
IMAGE="xteink-qemu-wasm-build"
JOBS="${JOBS:-$(nproc 2>/dev/null || echo 2)}"
if [ -n "${CONTAINER_ENGINE:-}" ]; then
ENGINE="$CONTAINER_ENGINE"
elif command -v podman >/dev/null; then
ENGINE=podman
else
ENGINE=docker
fi
if [ ! -d "$SRC/.git" ]; then
git clone --depth 1 --branch "$TAG" https://github.com/espressif/qemu "$SRC"
fi
cd "$SRC"
if [ "$(git rev-parse HEAD)" != "$COMMIT" ]; then
echo "QEMU source must be $COMMIT ($TAG)" >&2
exit 1
fi
# Re-apply Patches On Drift - The source tree is a build artifact of the patches; reset and re-apply whenever a patch is newer than the last apply so `make web` never silently rebuilds stale sources.
STAMP=".xteink-patch-stamp"
if [ ! -f hw/display/xteink_x3_eink.c ] || [ ! -f tcg/wasm32.c ] \
|| [ "$ROOT/qemu/patches/0001-xteink-machine.patch" -nt "$STAMP" ] \
|| [ "$ROOT/qemu/patches/0002-qemu-wasm.patch" -nt "$STAMP" ]; then
git reset --hard "$COMMIT"
git clean -fdx -e build
git apply "$ROOT/qemu/patches/0001-xteink-machine.patch"
git apply --whitespace=nowarn "$ROOT/qemu/patches/0002-qemu-wasm.patch"
touch "$STAMP"
fi
printf 'Building Emscripten environment (qemu-wasm %s)\n' "$QEMU_WASM_COMMIT"
"$ENGINE" build -t "$IMAGE" -f "$ROOT/qemu/wasm/Dockerfile" "$ROOT/qemu/wasm"
FLAGS="-O3 -Wno-error=unused-command-line-argument -matomics -mbulk-memory -DNDEBUG -DG_DISABLE_ASSERT -D_GNU_SOURCE -sASYNCIFY=1 -pthread -sPROXY_TO_PTHREAD=1 -sFORCE_FILESYSTEM -sALLOW_TABLE_GROWTH -sINITIAL_MEMORY=64MB -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1GB -sSTACK_SIZE=1048576 -sWASM_BIGINT -sMALLOC=mimalloc -sEXPORT_ES6=1 -sASYNCIFY_IMPORTS=ffi_call_js"
if [ ! -f build/build.ninja ] || ! grep -q 'block/vvfat.c' build/build.ninja; then
"$ENGINE" run --rm -v "$SRC:/qemu" "$IMAGE" bash -lc "
cd /qemu
emconfigure ./configure \\
--static \\
--target-list=riscv32-softmmu \\
--cpu=wasm32 \\
--cross-prefix= \\
--without-default-features \\
--without-default-devices \\
--with-devices-riscv32=xteink \\
--enable-system \\
--enable-qcow1 \\
--enable-vvfat \\
--with-coroutine=fiber \\
--disable-werror \\
--disable-docs \\
--disable-tools \\
--extra-cflags='$FLAGS' \\
--extra-cxxflags='$FLAGS' \\
--extra-ldflags='-sINITIAL_MEMORY=64MB -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1GB -sEXPORTED_RUNTIME_METHODS=getTempRet0,setTempRet0,addFunction,removeFunction,TTY,FS'
"
fi
"$ENGINE" run --rm -v "$SRC:/qemu" "$IMAGE" \
bash -lc "cd /qemu && emmake ninja -C build -j$JOBS qemu-system-riscv32.js"
mkdir -p "$OUT"
install -m 0644 build/qemu-system-riscv32.js "$OUT/"
install -m 0644 build/qemu-system-riscv32.wasm "$OUT/"
install -m 0644 build/qemu-system-riscv32.worker.js "$OUT/"
install -m 0644 pc-bios/esp32c3-rom.bin "$OUT/"
if command -v node >/dev/null; then
"$ROOT/scripts/smoke-qemu-wasm.sh" "$OUT/qemu-system-riscv32.js"
# Retry Bridge Smoke - Emscripten pthread startup has a rare transient trap during proxied entry; a second attempt clears it. Fail only if it never succeeds.
node "$ROOT/scripts/smoke-browser-bridge.mjs" "$OUT" \
|| node "$ROOT/scripts/smoke-browser-bridge.mjs" "$OUT"
fi
printf '%s\n' "$OUT"