boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

run.sh (7346B)


      1 #!/bin/sh
      2 ## tests/run.sh — host-side dispatcher for the unified test runner.
      3 ##
      4 ## All build/run/diff work happens inside the container via
      5 ## tests/run-suite.sh: this script just starts one podman
      6 ## process per requested arch and aggregates the per-arch
      7 ## PASS/FAIL totals. Prior versions of this runner re-entered the
      8 ## container per fixture (and per build/run within a fixture); now
      9 ## a whole arch's suite is one podman invocation.
     10 ##
     11 ## The one bit of work that stays on the host is the lint preflight
     12 ## for the m1pp and p1 suites: tools/lint.sh runs python, which the
     13 ## busybox container doesn't carry. Names that fail lint are reported
     14 ## here (FAIL + diagnostic) and excluded from the in-container batch.
     15 ##
     16 ## Suites:
     17 ##   m1pp     tests/M1pp/<name>.M1pp   — m1pp expander parity test.
     18 ##   p1       tests/P1/<name>.P1pp     — built via tests/build-p1pp.sh
     19 ##                                       and run; stdout diffed.
     20 ##            tests/P1/<name>.P1       — raw P1, built via
     21 ##                                       tests/build-p1.sh (no expander).
     22 ##   scheme1  tests/scheme1/<name>.scm — run by per-arch scheme1.
     23 ##   cc-util  tests/cc-util/<name>.scm — scheme1 prelude+util byte-diff.
     24 ##   cc-lex   tests/cc-lex/<name>.c    — lex pipeline byte-diff.
     25 ##   cc-pp    tests/cc-pp/<name>.c     — pp pipeline byte-diff (+ .scm).
     26 ##   cc-cg    tests/cc-cg/<name>.scm   — cg emit -> P1pp -> ELF -> run.
     27 ##   cc       tests/cc/<name>.c        — cc -> P1pp -> ELF -> run.
     28 ##   cc-ext   vendor/c-testsuite/single-exec/<name>.c — broad subset
     29 ##                                       coverage from the upstream
     30 ##                                       c-testsuite. needs-libc tests
     31 ##                                       link the mes-libc chain (same
     32 ##                                       as cc-libc); plain tests use
     33 ##                                       the bare cc pipeline. Any
     34 ##                                       compile/assemble/runtime error
     35 ##                                       counts as FAIL.
     36 ##   tcc-cc   tests/cc/<name>.c        — tcc-boot2 -> ELF -> run.
     37 ##   tcc-libc tests/cc-libc/<name>.c   — tcc-boot2 builds mes-libc into
     38 ##                                       libc.o, then compiles + links
     39 ##                                       each fixture against it -> run.
     40 ##
     41 ## Core and cc.scm suites run on all four bootstrap arches by default;
     42 ## suites consuming boot3+ TCC/libc artifacts retain three targets.
     43 ##
     44 ## Usage: tests/run.sh --suite <suite> [--arch ARCH] [name ...]
     45 
     46 set -eu
     47 
     48 SUITE=
     49 ARCH=
     50 NAMES=
     51 STAGE=
     52 
     53 while [ "$#" -gt 0 ]; do
     54     case "$1" in
     55         --suite)   shift; SUITE=$1 ;;
     56         --suite=*) SUITE=${1#--suite=} ;;
     57         --arch)    shift; ARCH=$1 ;;
     58         --arch=*)  ARCH=${1#--arch=} ;;
     59         --stage)   shift; STAGE=$1 ;;
     60         --stage=*) STAGE=${1#--stage=} ;;
     61         --) shift; while [ "$#" -gt 0 ]; do NAMES="$NAMES $1"; shift; done; break ;;
     62         -*) echo "$0: unknown flag '$1'" >&2; exit 2 ;;
     63         *) NAMES="$NAMES $1" ;;
     64     esac
     65     shift
     66 done
     67 
     68 case "$SUITE" in
     69     m1pp|p1|scheme1|cc-util|cc-lex|cc-pp|cc-cg|cc|cc-libc|cc-ext|tcc-cc|tcc-libc) ;;
     70     "") echo "$0: --suite required (m1pp | p1 | scheme1 | cc-util | cc-lex | cc-pp | cc-cg | cc | cc-libc | cc-ext | tcc-cc | tcc-libc)" >&2; exit 2 ;;
     71     *) echo "$0: unknown suite '$SUITE'" >&2; exit 2 ;;
     72 esac
     73 
     74 REPO=$(cd "$(dirname "$0")/.." && pwd)
     75 cd "$REPO"
     76 
     77 platform_of() {
     78     case "$1" in
     79         aarch64) echo linux/arm64 ;;
     80         amd64)   echo linux/amd64 ;;
     81         riscv64) echo linux/riscv64 ;;
     82         riscv32)
     83             native=$(podman info --format '{{.Host.Arch}}')
     84             case "$native" in aarch64) native=arm64 ;; x86_64) native=amd64 ;; esac
     85             echo "linux/$native"
     86             ;;
     87         *) echo "$0: unknown arch '$1'" >&2; return 1 ;;
     88     esac
     89 }
     90 
     91 run_in_container() {
     92     arch=$1; shift
     93     podman run --rm --pull=never --platform "$(platform_of "$arch")" \
     94         --tmpfs /tmp:size=512M \
     95         -e "ARCH=$arch" \
     96         -e "CC_TRACE_EMIT=${CC_TRACE_EMIT:-0}" \
     97         -e "CC_DEBUG=${CC_DEBUG:-0}" \
     98         -e "STAGE=${STAGE:-}" \
     99         -v "$REPO":/work -w /work \
    100         "boot2-busybox-test:$arch" "$@"
    101 }
    102 
    103 if [ -z "$ARCH" ]; then
    104     case "$SUITE" in
    105         cc-libc|cc-ext|tcc-cc|tcc-libc)
    106             ARCHES="aarch64 amd64 riscv64"
    107             ;;
    108         *) ARCHES="aarch64 amd64 riscv64 riscv32" ;;
    109     esac
    110 else
    111     ARCHES=$ARCH
    112 fi
    113 
    114 case "$SUITE:$ARCHES" in
    115     cc-libc:riscv32|cc-ext:riscv32|tcc-cc:riscv32|tcc-libc:riscv32)
    116         echo "$SUITE is unavailable for riscv32: it consumes the intentionally unimplemented TCC/libc stages" >&2
    117         exit 2
    118         ;;
    119 esac
    120 
    121 PASS=0
    122 FAIL=0
    123 
    124 # Lint preflight: lint.sh uses python (host-only). Discover the
    125 # fixture set if --names was empty, lint each raw fixture (.M1pp / .P1),
    126 # emit a host-side FAIL + diagnostic for any miss, write the kept name
    127 # list to $keep_file. FAIL line goes to stdout to interleave with the
    128 # container's PASS/FAIL output; the FAIL counter updates in-scope.
    129 #
    130 # Suite layout:
    131 #   m1pp: tests/M1pp/<name>.M1pp   (no raw .M1 fixtures any more)
    132 #   p1:   tests/P1/<name>.P1pp     (lint skipped — expander output)
    133 #         tests/P1/<name>.P1       (lint runs)
    134 lint_preflight() {
    135     arch=$1; keep_file=$2; dir=$3; raw_ext=$4; pp_ext=$5
    136     : > "$keep_file"
    137     if [ -z "$NAMES" ]; then
    138         raw=$(ls "$dir" 2>/dev/null \
    139              | sed -n "s/^\([^_][^.]*\)\.${raw_ext}\$/\1/p")
    140         pp=$(ls "$dir" 2>/dev/null \
    141              | sed -n "s/^\([^_][^.]*\)\.${pp_ext}\$/\1/p")
    142         all=$(printf '%s\n%s\n' "$raw" "$pp" | sort -u | tr '\n' ' ')
    143     else
    144         all=$NAMES
    145     fi
    146     for name in $all; do
    147         raw_src=$dir/$name.$raw_ext
    148         if [ -e "$raw_src" ] \
    149            && ! ARCH=$arch sh tools/lint.sh "$raw_src" >/dev/null 2>&1; then
    150             echo "  FAIL [$arch] $name"
    151             ARCH=$arch sh tools/lint.sh "$raw_src" 2>&1 \
    152                 | sed 's/^/    /' >&2 || true
    153             FAIL=$((FAIL + 1))
    154         else
    155             printf '%s ' "$name" >> "$keep_file"
    156         fi
    157     done
    158 }
    159 
    160 for arch in $ARCHES; do
    161     case "$SUITE" in
    162         m1pp) preflight_args="tests/M1pp M1 M1pp" ;;
    163         p1)   preflight_args="tests/P1 P1 P1pp" ;;
    164         *)    preflight_args= ;;
    165     esac
    166     if [ -n "$preflight_args" ]; then
    167         keep_file=$(mktemp)
    168         # shellcheck disable=SC2086 # $preflight_args is intentionally word-split.
    169         lint_preflight "$arch" "$keep_file" $preflight_args
    170         names=$(cat "$keep_file")
    171         rm -f "$keep_file"
    172         # Skip the container call only when the user gave names AND
    173         # all of them failed lint. With no names, an empty kept set
    174         # would mean nothing to run anyway.
    175         names_trimmed=$(echo "$names" | tr -d ' \t\n')
    176         if [ -z "$names_trimmed" ]; then
    177             continue
    178         fi
    179     else
    180         names=$NAMES
    181     fi
    182 
    183     out=$(mktemp)
    184     # shellcheck disable=SC2086 # $names is intentionally word-split.
    185     run_in_container "$arch" sh tests/run-suite.sh \
    186         --suite="$SUITE" $names | tee "$out"
    187     p=$(grep -c '^  PASS ' "$out" 2>/dev/null || true)
    188     f=$(grep -c '^  FAIL ' "$out" 2>/dev/null || true)
    189     PASS=$((PASS + ${p:-0}))
    190     FAIL=$((FAIL + ${f:-0}))
    191     rm -f "$out"
    192 done
    193 
    194 echo "$PASS passed, $FAIL failed"
    195 [ "$FAIL" -eq 0 ]