flan/test/cells.sh

74 lines
2.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Does a --x86 --dev build actually call through the indirection cell?
#
# survey.sh cannot answer this and no program can. A dev build begins with
# every cell pointing at the body this build compiled, so it prints exactly
# what a release build prints whether the call reads the cell or ignores it.
# The only way to tell is to change what a cell holds and see whether anything
# notices.
#
# So: cell-override.c is preloaded, and its constructor looks up
# flan.cell.twice with dlsym and stores a different body there. No compiler is
# involved and nothing is redefined in the language's sense -- this is just the
# one store a redefinition ends in, done from outside.
#
# Four builds, and the two controls are half the test:
#
# llvm --dev cell is read -> 22 22
# x86 --dev cell is read -> 22 22 (this lane's claim)
# llvm no cell -> 42 42 (dlsym answers NULL)
# x86 no cell -> 42 42
#
# The release rows are what say the change came from the indirection and not
# from ordinary symbol interposition.
set -u
here=$(cd "$(dirname "$0")" && pwd)
root=$(cd "$here/.." && pwd)
# FLAN overrides the compiler, and when it is set nothing is built here. The
# @cells alias sets it, because a dune action that shells out to dune waits on a
# lock it cannot get; main.exe is in that rule's deps instead. Resolved to an
# absolute path *before* the cd below, because dune's %{workspace_root} expands
# relative to the directory the rule is written in, and a relative path stops
# meaning what it meant the moment the working directory changes.
flan=
if [ -n "${FLAN:-}" ]; then
case $FLAN in /*) flan=$FLAN ;;
*) flan=$(cd "$(dirname "$FLAN")" && pwd)/$(basename "$FLAN") ;; esac
fi
cd "$root" || exit 1
if [ -z "$flan" ]; then
dune build --root . bin/main.exe 2>&1 | head -30
flan=$root/_build/default/bin/main.exe
fi
test -x "$flan" || { echo "no compiler at $flan"; exit 1; }
out=$(mktemp -d); trap 'rm -rf "$out"' EXIT
cc -shared -fPIC -o "$out/override.so" "$here/cell-override.c" || exit 1
src=$here/programs/x86-p8-cell.flan
fail=0
run() { # run <label> <expected> <build flags...>
local label=$1 want=$2; shift 2
if ! "$flan" build "$src" "$@" -o "$out/p8" >"$out/build.err" 2>&1; then
echo "FAIL $label: build failed"; head -3 "$out/build.err"; fail=1; return
fi
local got
got=$(cd "$out" && LD_PRELOAD="$out/override.so" ./p8 | tr '\n' ' ')
got=${got% }
if [ "$got" = "$want" ]; then
echo "ok $label: $got"
else
echo "FAIL $label: expected '$want', got '$got'"; fail=1
fi
}
run "llvm --dev" "22 22" --dev
run "x86 --dev" "22 22" --dev --x86
run "llvm " "42 42"
run "x86 " "42 42" --x86
exit $fail