#!/usr/bin/env bash # The operator-set module, built and checked: the module of record of WAISM's integer level. # # bash wai/wai-int-module/build.sh [--out DIR] # # Builds the crate for wasm32-unknown-unknown twice, each with its own target directory: # # wai_int.wasm scalar # wai_int.simd128.wasm with SIMD128 (-C target-feature=+simd128): the same source, which # the compiler lowers to WebAssembly's integer vector instructions # where it can # # and holds each to the profile with both of its checkers (../wai-module-check): the Rust # checker and check-module.mjs must each give `held` at the integer level, and the two must # give the same verdict at both levels. Then it writes each to DIR (default: the target # directory's `module/`) and prints its size and SHA-256. (`host/`'s `--count` says how many # of each build's instructions are 128-bit vector instructions.) # # The module names no path of this machine: the checkout, the Cargo home and the toolchain are # remapped to /open-standards, /cargo and /rustup, as reach/record's package was built. Its # bytes still depend on where and on what it is built: the compiler's crate hashes take in the # absolute path of each path dependency and the host the compiler runs on, and they order what # it emits. So record/ is named by its SHA-256 (record/manifest.json), and what a build of # this source on another host or from another checkout shows is the outputs: every case of # the corpus the same. # # Needs bash, cargo with the wasm32-unknown-unknown target of the pinned toolchain, python3 # and node >= 18. set -euo pipefail CRATE="$(cd "$(dirname "$0")" && pwd -P)" WAI="$(cd "$CRATE/.." && pwd -P)" ROOT="$(cd "$WAI/.." && pwd -P)" OUT= while [ $# -gt 0 ]; do case "$1" in --out) OUT="$2"; shift 2 ;; *) echo "usage: bash build.sh [--out DIR]" >&2; exit 2 ;; esac done for t in cargo rustc node python3; do command -v "$t" >/dev/null || { echo "wai-int-module: needs $t" >&2; exit 1; } done cd "$CRATE" TARGET_BASE="${CARGO_TARGET_DIR:-$CRATE/target}" OUT="${OUT:-$TARGET_BASE/module}" mkdir -p "$OUT" CARGO_HOME_DIR="$(cd "${CARGO_HOME:-$HOME/.cargo}" && pwd -P)" RUSTUP_HOME_DIR="$(cd "${RUSTUP_HOME:-$HOME/.rustup}" && pwd -P)" REMAP="--remap-path-prefix=$ROOT=/open-standards --remap-path-prefix=$CARGO_HOME_DIR=/cargo --remap-path-prefix=$RUSTUP_HOME_DIR=/rustup" # The checker, built once. cargo build --locked --release -q --manifest-path "$WAI/wai-module-check/Cargo.toml" --target-dir "$TARGET_BASE/checker" CHECK="$TARGET_BASE/checker/release/wai-module-check" for variant in scalar simd128; do flags="$REMAP" name=wai_int.wasm if [ "$variant" = simd128 ]; then flags="$flags -C target-feature=+simd128" name=wai_int.simd128.wasm fi RUSTFLAGS="$flags" cargo build --locked --release --target wasm32-unknown-unknown --target-dir "$TARGET_BASE/$variant" built="$TARGET_BASE/$variant/wasm32-unknown-unknown/release/wai_int_module.wasm" [ -f "$built" ] || { echo "wai-int-module: the build left no $built" >&2; exit 1; } rm -f "$OUT/$name" # Both checkers, at both levels: held at the integer level, and the same verdict at each. for level in integer float; do rust=$("$CHECK" --level "$level" "$built" || true) js=$(node "$WAI/wai-module-check/check-module.mjs" --level "$level" "$built" || true) if [ "$rust" != "$js" ]; then echo "wai-int-module: $variant at the $level level: the Rust checker says '$rust', check-module.mjs '$js'" >&2 exit 1 fi if [ "$rust" != held ]; then echo "wai-int-module: $variant is not held at the $level level: $rust" >&2 exit 1 fi done cp "$built" "$OUT/$name" sum=$(python3 -I -c 'import hashlib,sys; print(hashlib.sha256(open(sys.argv[1],"rb").read()).hexdigest())' "$OUT/$name") size=$(wc -c < "$OUT/$name" | tr -d ' ') echo "wai-int-module: $OUT/$name: $size bytes, SHA-256 $sum, held at the integer level by both checkers" done