blaise/scripts/freebsd-crosscheck-build.sh
Graeme Geldenhuys 0ee32e51f5 ci(freebsd): run cross-compiled FreeBSD binaries under emulation (Step 8)
Host-side static ELF checks (EI_OSABI/ET_EXEC/no-PT_INTERP, already asserted by
TInternalLinkerE2ETests.TestCompile_FreeBSDTarget_EmitsStaticFreeBSDExe) cannot
catch a wrong FreeBSD struct-stat offset or syscall number — only running the
binary on a real FreeBSD kernel does.

Add a freebsd-crosscheck CI job (needs: bootstrap) that:
  * downloads the -pre binary the bootstrap job built,
  * cross-compiles the fixtures in compiler/src/it/freebsd (hello, fileio) with
    --target freebsd-x86_64 on the Linux runner via
    scripts/freebsd-crosscheck-build.sh (which also sanity-checks each emitted
    ELF is a FreeBSD ET_EXEC), and
  * boots a FreeBSD VM (vmactions/freebsd-vm, release 14.2 to match the
    struct-stat offsets in rtl.platform.layout.freebsd) and runs the binaries
    there, asserting hello prints 'Hello' and fileio round-trips a file
    (write/read/stat/delete) with 'file-io-ok'/'exists-ok'/'done'.

The FreeBSD output is a static, freestanding raw-syscall ET_EXEC, so the VM
needs no extra packages to run it.  fileio is the meaningful check: it exercises
open/write/read/stat/unlink through the FreeBSD leaf and layout, which the
static checks are blind to.
2026-07-01 17:28:07 +01:00

74 lines
2.5 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Cross-compile the FreeBSD emulation-check fixtures (compiler/src/it/freebsd/*.pas)
# with --target freebsd-x86_64 on a Linux host. The resulting static, freestanding
# FreeBSD ET_EXEC binaries are then run inside a FreeBSD VM (see the freebsd-crosscheck
# job in .github/workflows/bootstrap.yml) to validate the FreeBSD syscall leaf and
# struct-stat layout that host-side static ELF checks cannot catch.
#
# Usage:
# BLAISE=/path/to/blaise scripts/freebsd-crosscheck-build.sh [OUTDIR]
#
# BLAISE path to a native-backend blaise binary that supports --target
# freebsd-x86_64 (defaults to compiler/target/blaise).
# OUTDIR where to write the cross-compiled binaries (defaults to
# target/freebsd-crosscheck).
#
# The binaries CANNOT run on the Linux host (FreeBSD syscall numbers/ABI); this
# script only builds and sanity-checks the emitted ELF shape. Prints
# FREEBSD_CROSSBUILD_OK on success.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
BLAISE="${BLAISE:-compiler/target/blaise}"
OUTDIR="${1:-target/freebsd-crosscheck}"
FIXDIR="compiler/src/it/freebsd"
if [ ! -x "$BLAISE" ]; then
echo "error: blaise binary not found or not executable: $BLAISE" >&2
exit 1
fi
mkdir -p "$OUTDIR"
# The compiler resolves blaise_rtl.a / the RTL source relative to its own binary;
# the RTL source lives in the compiler tree. Both unit paths mirror the normal
# native build.
UNIT_ARGS=(
--unit-path runtime/src/main/pascal
--unit-path stdlib/src/main/pascal
)
for src in "$FIXDIR"/*.pas; do
name="$(basename "$src" .pas)"
out="$OUTDIR/$name"
echo "cross-compiling $src -> $out (freebsd-x86_64)"
"$BLAISE" \
--source "$src" \
--backend native \
--target freebsd-x86_64 \
--output "$out" \
"${UNIT_ARGS[@]}"
# Sanity-check the emitted ELF is a FreeBSD (EI_OSABI=9) ET_EXEC. readelf is
# part of binutils, always present on the Linux runner.
osabi="$(readelf -hW "$out" | awk -F: '/OS\/ABI/ {print $2}' | xargs)"
etype="$(readelf -hW "$out" | awk -F: '/Type:/ {print $2}' | awk '{print $1}')"
case "$osabi" in
*FreeBSD*) : ;;
*) echo "error: $out is not a FreeBSD binary (OS/ABI=$osabi)" >&2; exit 1 ;;
esac
if [ "$etype" != "EXEC" ]; then
echo "error: $out is not a static ET_EXEC (Type=$etype)" >&2
exit 1
fi
done
# Drop the .o intermediates the compiler leaves beside each output, so the VM
# job can run every executable in OUTDIR without tripping over object files.
rm -f "$OUTDIR"/*.o
echo "FREEBSD_CROSSBUILD_OK"