#!/usr/bin/env bash # Build the entire W65816 runtime — assemble *.s, compile *.c. # Run after editing anything under runtime/src/. set -euo pipefail PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" LLVM_MC="$PROJECT_ROOT/tools/llvm-mos-build/bin/llvm-mc" CLANG="$PROJECT_ROOT/tools/llvm-mos-build/bin/clang" # Apply CPU/memory caps so a runaway backend bug can't OOM-kill the # entire tmux scope. Use `|| true` so when invoked from a parent that # has already lowered the limit (e.g. smokeTest.sh sets 90s), we keep # the parent's tighter cap rather than failing the build. ulimit -v $((10 * 1024 * 1024)) 2>/dev/null || true ulimit -t 1200 2>/dev/null || true [ -x "$LLVM_MC" ] || { echo "llvm-mc not found at $LLVM_MC" >&2; exit 1; } [ -x "$CLANG" ] || { echo "clang not found at $CLANG" >&2; exit 1; } SRC="$PROJECT_ROOT/runtime/src" OUT="$PROJECT_ROOT/runtime" asm() { local s="$1" local o="$OUT/$(basename "${s%.s}").o" echo " AS $(basename "$s")" "$LLVM_MC" -arch=w65816 -filetype=obj "$s" -o "$o" } cc() { local c="$1" local o="$OUT/$(basename "${c%.c}").o" local extra=("${@:2}") echo " CC $(basename "$c")" "$CLANG" -target w65816 -O2 -ffunction-sections \ "${extra[@]}" \ -I"$PROJECT_ROOT/runtime/include" \ -c "$c" -o "$o" } asm "$SRC/crt0.s" asm "$SRC/crt0Gsos.s" asm "$SRC/crt0Gno.s" asm "$SRC/gnoKernel.s" asm "$SRC/gnoGsos.s" cc "$SRC/libcGno.c" asm "$SRC/libgcc.s" cc "$SRC/libc.c" cc "$SRC/strtol.c" cc "$SRC/snprintf.c" # Float-less snprintf for smoke checks that overshoot the single-bank # IIgs IO window at $C000-$CFFF. Same source file, gated by # LLVM816_NO_FLOAT_PRINTF — skips emitDouble / emitHexFloat / decodeDouble # / emitInfNan AND the float dispatch arms in format(), so the linker # drops the softFloat / softDouble pull-in entirely. echo " CC snprintf.c (no-float)" "$CLANG" -target w65816 -O2 -ffunction-sections -DLLVM816_NO_FLOAT_PRINTF \ -I"$PROJECT_ROOT/runtime/include" \ -c "$SRC/snprintf.c" -o "$OUT/snprintfNoFloat.o" cc "$SRC/sscanf.c" cc "$SRC/qsort.c" cc "$SRC/extras.c" cc "$SRC/strtok.c" cc "$SRC/timeExt.c" cc "$SRC/math.c" cc "$SRC/softFloat.c" cc "$SRC/libcxxabi.c" cc "$SRC/libcxxabiSjlj.c" cc "$SRC/libunwindStub.c" cc "$SRC/desktop.c" cc "$SRC/sound.c" cc "$SRC/cursor.c" cc "$SRC/sprite.c" cc "$SRC/eventLoop.c" cc "$SRC/uiBuilder.c" # resource.c is Phase 3.4 STUB-ONLY: bundler + linker integration ship, # runtime LoadResource() returns RES_ERR_BLOCKED until Phase 1.1 (GS/OS # fopen hang) lands. Build it unconditionally so the typed-C facade # links from any demo; the body is a 2-instruction stub today. cc "$SRC/resource.c" asm "$SRC/iigsGsos.s" asm "$SRC/iigsToolbox.s" # softDouble.c builds at -O2. dpack is noinline to dodge a backend # stack-slot aliasing bug; dclass stays inline because pointer-arg # stores from a noinline boundary use DBR-relative addressing (broken # under DBR != 0). Both choices documented in the source. cc "$SRC/softDouble.c" # Phase 6.2 UBSan-min runtime. MUST be compiled with # `-fno-sanitize=undefined` — without that, the handlers would self- # instrument on every integer op and recurse infinitely the first time # UBSan fires. Routed via the existing cc() helper but with the extra # flag appended. Built unconditionally so any user passing # `-fsanitize=undefined -fsanitize-minimal-runtime` to their compile + # `runtime/ubsan.o` to their link gets a fully-resolved symbol set. cc "$SRC/ubsan.c" -fno-sanitize=undefined # Emit a manifest listing every .o this build produced. CMake (Phase # 2.6 of the gap-closure plan) consumes this as the single source of # truth for the runtime object list, so a `file(GLOB)` in CMake doesn't # pick up stale .bak files or out-of-tree leftovers. One basename per # line (no path, no extension); sorted for diff-stability. MANIFEST="$OUT/.runtime-imports.list" { echo "# runtime object manifest — produced by runtime/build.sh" echo "# Format: one .o filename per line (relative to runtime/)." echo "# Single source of truth for the W65816 runtime object set." echo "# Do not edit by hand; rerun runtime/build.sh to regenerate." ls -1 "$OUT"/*.o 2>/dev/null | xargs -n1 basename | sort } >"$MANIFEST" echo "runtime built: $(ls -1 "$OUT"/*.o | wc -l) objects" echo "manifest: $MANIFEST"