commit e588f2ff4cc4f95d7eab3cfd1847b490eb157c5f
parent c89c279bfba06ba19c63e497e07187f08da8ab1f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 17 Jun 2026 15:45:52 -0700
test: test-t1-cross for cross-compile and cross-link
Diffstat:
6 files changed, 269 insertions(+), 0 deletions(-)
diff --git a/mk/test.mk b/mk/test.mk
@@ -214,6 +214,7 @@ TIER1_TEST_TARGETS = \
test-t1-asm-disas \
test-t1-obj \
test-t1-link-jit \
+ test-t1-cross \
test-t1-rt \
test-t1-debug \
test-t1-emu-interp \
@@ -276,6 +277,9 @@ test-t1-link-jit: $(LINK_EXE_RUNNER)
@$(T1_LOG) link test/tier1/objlink/link.sh
@$(T1_LOG) jit-relax $(MAKE) --no-print-directory test-link-jit-tls-relax
+test-t1-cross: bin
+ @$(T1_LOG) cross env KIT=$(abspath $(BIN)) test/tier1/cross/run.sh
+
test-t1-rt:
@$(T1_LOG) rt test/tier1/system/runtime-headers.sh
diff --git a/test/TESTMAP.md b/test/TESTMAP.md
@@ -13,6 +13,7 @@ area you changed.
| `src/asm/**`, `driver/cmd/as.c`, `driver/cmd/disas.c` | `make test-t1-asm-disas` | `make test-asm` |
| `src/obj/**`, object format readers/writers | `make test-t1-obj` | `make test-elf test-macho test-coff` |
| `src/link/**`, JIT image mapping | `make test-t1-link-jit` | `make test-link` |
+| cross hosted profiles, sysroot resolution, target triples | `make test-t1-cross` | `make test-cross TARGET=<selector> DEPTH=smoke` |
| `rt/**` | `make test-t1-rt` | `make test-rt-runtime test-rt-backtrace` |
| `src/debug/**`, `src/dbg/**` | `make test-t1-debug` | `make test-debug test-dwarf test-dbg` |
| `src/emu/**`, `src/interp/**` | `make test-t1-emu-interp` | `make test-emu test-emu-unit test-interp` |
diff --git a/test/tier1/README.md b/test/tier1/README.md
@@ -13,5 +13,9 @@ Rules:
- If a Tier 1 sentinel fails, run the matching focused suite from
`test/TESTMAP.md`.
+The cross sentinel is build/link-only. It covers the supported cross matrix and
+reports missing provisioned sysroots or SDKs as SKIP with exit 0. Narrow it with
+`T1_CROSS_TARGETS=<selector>` when needed.
+
`make test` runs Tier 1 in parallel. The previous broad default is available as
`make test-full`.
diff --git a/test/tier1/cross/README.md b/test/tier1/cross/README.md
@@ -0,0 +1,24 @@
+# Cross Tier 1
+
+`run.sh` is the Tier 1 cross-compile/link sentinel. It covers the portability
+support set at build/link depth only; it does not execute target artifacts.
+
+Missing provisioned sysroots or SDKs are reported as `SKIP` and exit 0. Real
+compile/link failures are `FAIL`.
+
+Covered lanes:
+
+- `linux-{glibc,musl}-{aa64,x64,rv64}`; musl runs both `static` and `dynamic`
+ link modes.
+- `freebsd-{aa64,x64,rv64}`.
+- `windows-{aa64,x64}`.
+- `android-aa64` as a shared `NativeActivity` build.
+- `macos-{aa64,x64}` when the macOS SDK is available on Darwin.
+- `ios-aa64`, `ios-sim-{aa64,x64}` when the relevant Xcode SDK is available.
+- `freestanding-{aa64,x64,rv64,rv32,arm32}` with compile plus `kit ld`.
+
+Provision hosted sysroots with:
+
+```sh
+make provision TARGET=<selector>
+```
diff --git a/test/tier1/cross/run.sh b/test/tier1/cross/run.sh
@@ -0,0 +1,230 @@
+#!/usr/bin/env bash
+set -u
+
+ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
+KIT="${KIT:-$ROOT/build/kit}"
+HOSTED="$ROOT/scripts/hosted.sh"
+CASES="$ROOT/test/cross/cases"
+WORK="$ROOT/build/test/tier1/cross"
+SELECTOR="${T1_CROSS_TARGETS:-all}"
+
+mkdir -p "$WORK"
+
+. "$ROOT/test/lib/kit_sh_report.sh"
+kit_report_init
+KIT_SKIP_IS_FAILURE=0
+
+if [ ! -x "$KIT" ]; then
+ kit_fail "cross/setup" "kit not built at $KIT"
+ kit_summary test-t1-cross
+ kit_exit
+fi
+
+match_selector() {
+ local lane="$1" sel item
+ sel="$(printf '%s' "$SELECTOR" | tr , ' ')"
+ [ "$sel" = all ] && return 0
+ for item in $sel; do
+ case "$lane" in
+ "$item"|"$item"-*|*-"$item") return 0 ;;
+ esac
+ case "$item:$lane" in
+ linux:"linux-"*|linux-glibc:"linux-glibc-"*|linux-musl:"linux-musl-"*) return 0 ;;
+ freebsd:"freebsd-"*|windows:"windows-"*|android:"android-"*) return 0 ;;
+ macos:"macos-"*|ios:"ios-"*|freestanding:"freestanding-"*) return 0 ;;
+ esac
+ done
+ return 1
+}
+
+hosted_path() {
+ "$HOSTED" path "$1" 2>/dev/null || true
+}
+
+hosted_triple() {
+ "$HOSTED" triple "$1" 2>/dev/null || true
+}
+
+hosted_needs_sysroot() {
+ case "$1" in
+ linux-*|freebsd-*|windows-*|android-*) return 0 ;;
+ *) return 1 ;;
+ esac
+}
+
+mode_flag() {
+ case "$1" in static) printf '%s\n' -static ;; *) printf '\n' ;; esac
+}
+
+run_cmd() {
+ local label="$1" log="$2"
+ shift 2
+ if "$@" >"$log" 2>&1; then
+ return 0
+ fi
+ kit_fail "$label" "see $log"
+ return 1
+}
+
+hosted_lane() {
+ local token="$1" mode="$2" label="$1" sysroot triple dir obj exe flag
+ [ "$mode" != default ] && label="$label:$mode"
+ match_selector "$token" || return 0
+
+ triple="$(hosted_triple "$token")"
+ if [ -z "$triple" ]; then
+ kit_skip "$label" "not in hosted support set"
+ return 0
+ fi
+
+ if hosted_needs_sysroot "$token"; then
+ sysroot="$(hosted_path "$token")"
+ if [ -z "$sysroot" ] || [ ! -d "$sysroot" ]; then
+ kit_skip "$label" "sysroot not provisioned; run: make provision TARGET=$token"
+ return 0
+ fi
+ fi
+
+ case "$token" in
+ macos-*)
+ if [ "$(uname -s 2>/dev/null)" != Darwin ]; then
+ kit_skip "$label" "macOS cross-link requires Darwin SDK host"
+ return 0
+ fi
+ if ! xcrun --sdk macosx --show-sdk-path >/dev/null 2>&1; then
+ kit_skip "$label" "macOS SDK unavailable"
+ return 0
+ fi ;;
+ esac
+
+ dir="$WORK/$label"
+ mkdir -p "$dir"
+ obj="$dir/exit.o"
+ exe="$dir/exit"
+ case "$token" in windows-*) exe="$exe.exe" ;; esac
+ flag="$(mode_flag "$mode")"
+
+ run_cmd "$label:cc" "$dir/cc.log" \
+ "$HOSTED" cc "$token" -O1 -c "$CASES/exit.c" -o "$obj" || return 0
+ # shellcheck disable=SC2086
+ run_cmd "$label:ld" "$dir/ld.log" \
+ "$HOSTED" cc "$token" $flag "$obj" -o "$exe" || return 0
+
+ if [ -s "$exe" ]; then
+ kit_pass "$label"
+ else
+ kit_fail "$label" "linked artifact missing"
+ fi
+}
+
+android_lane() {
+ local token=android-aa64 label=android-aa64 sysroot dir obj so
+ match_selector "$token" || return 0
+ sysroot="$(hosted_path "$token")"
+ if [ -z "$sysroot" ] || [ ! -d "$sysroot" ]; then
+ kit_skip "$label" "Android NDK sysroot not provisioned; run: make provision TARGET=$token"
+ return 0
+ fi
+ dir="$WORK/$label"
+ mkdir -p "$dir"
+ obj="$dir/native_activity.o"
+ so="$dir/libkit_native_activity.so"
+ run_cmd "$label:cc" "$dir/cc.log" \
+ "$HOSTED" cc "$token" -O1 -fPIC -c "$CASES/native_activity.c" -o "$obj" || return 0
+ run_cmd "$label:ld" "$dir/ld.log" \
+ "$HOSTED" cc "$token" -shared "$obj" -landroid -o "$so" || return 0
+ if [ -s "$so" ]; then kit_pass "$label"; else kit_fail "$label" "shared object missing"; fi
+}
+
+apple_sdk_path() {
+ local sdk="$1"
+ xcrun --sdk "$sdk" --show-sdk-path 2>/dev/null || true
+}
+
+apple_lane() {
+ local lane="$1" triple="$2" sdk_name="$3" label="$1" sdk dir obj exe
+ match_selector "$lane" || return 0
+ if [ "$(uname -s 2>/dev/null)" != Darwin ]; then
+ kit_skip "$label" "$sdk_name SDK requires Darwin host"
+ return 0
+ fi
+ sdk="$(apple_sdk_path "$sdk_name")"
+ if [ -z "$sdk" ] || [ ! -d "$sdk" ]; then
+ kit_skip "$label" "$sdk_name SDK unavailable"
+ return 0
+ fi
+ dir="$WORK/$label"
+ mkdir -p "$dir"
+ obj="$dir/exit.o"
+ exe="$dir/exit"
+ run_cmd "$label:cc" "$dir/cc.log" \
+ "$KIT" cc -target "$triple" --sysroot "$sdk" -O1 -c "$CASES/exit.c" -o "$obj" || return 0
+ run_cmd "$label:ld" "$dir/ld.log" \
+ "$KIT" cc -target "$triple" --sysroot "$sdk" "$obj" -lc -o "$exe" || return 0
+ if [ -s "$exe" ]; then kit_pass "$label"; else kit_fail "$label" "linked artifact missing"; fi
+}
+
+freestanding_triple() {
+ case "$1" in
+ aa64) echo aarch64-none-elf ;;
+ x64) echo x86_64-none-elf ;;
+ rv64) echo riscv64-none-elf ;;
+ rv32) echo riscv32-none-elf ;;
+ arm32) echo arm-none-eabi ;;
+ *) return 1 ;;
+ esac
+}
+
+freestanding_extra_flags() {
+ case "$1" in
+ rv32) printf '%s\n' "-march=rv32imafc_zicsr_zifencei -mabi=ilp32f" ;;
+ arm32) printf '%s\n' "-mcpu=cortex-m3 -mfloat-abi=soft" ;;
+ *) printf '\n' ;;
+ esac
+}
+
+freestanding_lane() {
+ local arch="$1" token="freestanding-$1" triple dir obj exe extra
+ match_selector "$token" || return 0
+ triple="$(freestanding_triple "$arch")" || {
+ kit_skip "$token" "unsupported freestanding arch"
+ return 0
+ }
+ dir="$WORK/$token"
+ mkdir -p "$dir"
+ obj="$dir/exit.o"
+ exe="$dir/exit.elf"
+ extra="$(freestanding_extra_flags "$arch")"
+ # shellcheck disable=SC2086
+ run_cmd "$token:cc" "$dir/cc.log" \
+ "$KIT" cc -target "$triple" $extra -O1 -ffreestanding -nostdlib \
+ -c "$CASES/exit.c" -o "$obj" || return 0
+ run_cmd "$token:ld" "$dir/ld.log" \
+ "$KIT" ld -e main -o "$exe" "$obj" || return 0
+ if [ -s "$exe" ]; then kit_pass "$token"; else kit_fail "$token" "linked artifact missing"; fi
+}
+
+for arch in aa64 x64 rv64; do
+ hosted_lane "linux-glibc-$arch" default
+ hosted_lane "linux-musl-$arch" static
+ hosted_lane "linux-musl-$arch" dynamic
+ hosted_lane "freebsd-$arch" static
+done
+
+for arch in aa64 x64; do
+ hosted_lane "windows-$arch" default
+ hosted_lane "macos-$arch" default
+done
+
+android_lane
+
+apple_lane ios-aa64 arm64-apple-ios iphoneos
+apple_lane ios-sim-aa64 arm64-apple-ios-simulator iphonesimulator
+apple_lane ios-sim-x64 x86_64-apple-ios-simulator iphonesimulator
+
+for arch in aa64 x64 rv64 rv32 arm32; do
+ freestanding_lane "$arch"
+done
+
+kit_summary test-t1-cross
+kit_exit
diff --git a/test/tier1/run_logged.sh b/test/tier1/run_logged.sh
@@ -21,4 +21,10 @@ if [ "$rc" -ne 0 ]; then
tail -100 "$log" >&2 || true
exit "$rc"
fi
+skips="$(sed -n 's/^[^:][^:]*: skipped: //p' "$log" | tr '\n' ' ' | sed -e 's/[[:space:]][[:space:]]*/ /g' -e 's/^ //' -e 's/ $//')"
+if [ -n "$skips" ]; then
+ nskip="$(printf '%s\n' "$skips" | wc -w | tr -d '[:space:]')"
+ printf 'T1 %-18s OK (%s skip: %s)\n' "$label" "$nskip" "$skips"
+ exit 0
+fi
printf 'T1 %-18s OK\n' "$label"