aboutsummaryrefslogtreecommitdiff
path: root/src/boot/boot.sh
blob: c7eb2ed1f4ee5c9443bf40e610645be0541f0b22 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/sh
# bootstraps the compiler from the pinned wasm seed. usage: src/boot/boot.sh OUTDIR
# checks seed/zc.wasm against seed/MANIFEST, then under a wasm runtime (wasmtime, or
# node) the seed compiles the compiler sources to g1 and g1 compiles them to g2; when
# they differ g2 compiles them to g3 and g2 = g3 is required (the fixpoint). the result is
# OUTDIR/genome.bin. the seed is proven by the fixpoint, not trusted. nothing here
# uses the c core.
set -e
cd "$(dirname "$0")/../.."
OUT=${1:?outdir}; SEED=${SEED:-seed/zc.wasm}; MAN=${MAN:-seed/MANIFEST}
mkdir -p "$OUT"
sha() { if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1; else shasum -a 256 "$1" | cut -d' ' -f1; fi; }
want=$(sed -n 's/^seed-sha256 //p' "$MAN"); got=$(sha "$SEED")
if [ -z "$BOOT_NOCHECK" ] && [ "$want" != "$got" ]; then
	echo "boot: $SEED does not match $MAN" >&2
	echo "boot:   manifest sha256 $want" >&2
	echo "boot:   file     sha256 $got" >&2
	echo "boot: the seed was changed or damaged; restore it from git, or run make seed to rebuild it on purpose" >&2
	exit 1
fi
if [ -n "$WASM_RUNTIME" ]; then RT=$WASM_RUNTIME
elif command -v wasmtime >/dev/null 2>&1; then RT=wasmtime
elif command -v node >/dev/null 2>&1 && node -e 'process.exit(+process.versions.node.split(".")[0] < 18 ? 1 : 0)' 2>/dev/null; then RT=node
else
	echo "boot: no WebAssembly runtime found. the compiler is built from seed/zc.wasm under one of:" >&2
	echo "boot:   node 18 or later   (macOS: brew install node;     debian/ubuntu: apt install nodejs)" >&2
	echo "boot:   wasmtime           (macOS: brew install wasmtime; elsewhere: curl https://wasmtime.dev/install.sh -sSf | bash)" >&2
	exit 1
fi
run() { case "$RT" in node) node src/boot/run.mjs "$1" ;; wasmtime) wasmtime run --dir=. "$1" ;; *) $RT "$1" ;; esac; }
le64() { n=$1 i=0; while [ $i -lt 8 ]; do printf "\\$(printf %03o $(( (n >> (8 * i)) & 255 )))"; i=$((i + 1)); done; }
SRC="src/runtime/rt.zc src/core/core.zc $(sed 's#^#src/compiler/#' src/compiler/parts | tr '\n' ' ')"
input() { cat src/tools/build.zc; printf '`'; cat $SRC; }
stage() { # stage IMAGE OUT: IMAGE empty means the seed's own genome
	{ if [ -n "$1" ]; then printf 'ZCIMAGE\n'; le64 $(wc -c < "$1"); cat "$1"; fi; input; } | run "$SEED" > "$2.tmp"
	mv "$2.tmp" "$2"
}
echo "boot: seed $got ok, runtime $RT"
stage "" "$OUT/g1.bin"; echo "boot: g1 (seed -> sources): $(sha "$OUT/g1.bin")"
[ "${BOOT_STAGES:-}" = 1 ] && exit 0
img=$(sed -n 's/^image-sha256 //p' "$MAN")
[ -n "$img" ] && { [ "$img" = "$(sha "$OUT/g1.bin")" ] && echo "boot: g1 is the image the manifest records" || echo "boot: g1 differs from the manifest's image (the sources changed since the seed was made)"; }
stage "$OUT/g1.bin" "$OUT/g2.bin"; echo "boot: g2 (g1 -> sources): $(sha "$OUT/g2.bin")"
if cmp -s "$OUT/g1.bin" "$OUT/g2.bin"; then
	# g1 rebuilt itself unchanged, so it is the fixpoint: a third stage would only repeat it
	cp "$OUT/g2.bin" "$OUT/genome.bin"; echo "boot: fixpoint (g1 = g2)"; exit 0
fi
stage "$OUT/g2.bin" "$OUT/g3.bin"; echo "boot: g3 (g2 -> sources): $(sha "$OUT/g3.bin")"
cmp "$OUT/g2.bin" "$OUT/g3.bin" || { echo "boot: no fixpoint: g2 and g3 differ" >&2; exit 1; }
cp "$OUT/g2.bin" "$OUT/genome.bin"; echo "boot: fixpoint (g2 = g3)"