-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbootstrap.sh
More file actions
executable file
·140 lines (120 loc) · 6.13 KB
/
bootstrap.sh
File metadata and controls
executable file
·140 lines (120 loc) · 6.13 KB
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/env bash
#
# bootstrap.sh — Multi-stage bootstrap for the Nexus self-hosted compiler (src/)
#
# Stage 0: Rust compiler (nexus build) compiles src/driver.nx → stage0.wasm
# Stage 1: Run stage0.wasm (nexus exec) to compile src/driver.nx → stage1.wasm
# Stage 2: Run stage1.wasm (nexus exec) to compile src/driver.nx → stage2.wasm
# Verify: stage1.wasm == stage2.wasm (fixed point)
#
# Usage: ./bootstrap.sh [--ci]
# --ci Strict mode for CI: fail on stage2 failure or non-identical output
#
set -euo pipefail
CI_MODE=false
for arg in "$@"; do
case "$arg" in
--ci) CI_MODE=true ;;
*) echo "Unknown argument: $arg" >&2; exit 1 ;;
esac
done
NEXUS="${NEXUS:-./bootstrap/target/release/nexus}"
NEXUS_ENTRY="src/driver.nx"
WASMTIME="${WASMTIME:-wasmtime}"
# Stage0 is a component (from nexus build); stage1+ are core WASM (from src/ with stdlib merge)
WASMTIME_FLAGS_COMPONENT="-W tail-call=y,exceptions=y,component-model=y,max-memory-size=8589934592 -S http,inherit-network --dir=. --dir=${TMPDIR:-/tmp}"
WASMTIME_FLAGS_CORE="-W tail-call=y,exceptions=y,max-memory-size=8589934592 --dir=. --dir=${TMPDIR:-/tmp}"
NEXUS_BUILD_FLAGS=""
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
RESET='\033[0m'
info() { printf "${CYAN}[bootstrap]${RESET} %s\n" "$*"; }
ok() { printf "${GREEN}[bootstrap]${RESET} %s\n" "$*"; }
warn() { printf "${YELLOW}[bootstrap]${RESET} %s\n" "$*"; }
fail() { printf "${RED}[bootstrap]${RESET} %s\n" "$*" >&2; exit 1; }
# ─── Temp directory ──────────────────────────────────────────────────────
BUILD_DIR="$(mktemp -d)"
cleanup() { rm -rf "$BUILD_DIR"; }
trap cleanup EXIT
info "Build directory: $BUILD_DIR"
# ─── Build the Nexus compiler (Rust) ──────────────────────────────────────
CURRENT_COMMIT="$(git rev-parse HEAD)"
info "Building Nexus compiler (cargo build --release --manifest-path bootstrap/Cargo.toml)..."
cargo build --release --manifest-path bootstrap/Cargo.toml
[[ -x "$NEXUS" ]] || fail "Nexus compiler not found at $NEXUS"
info "Using Nexus compiler: $NEXUS (commit ${CURRENT_COMMIT:0:7})"
# ─── Stage 0: Rust compiler → stage0.wasm ─────────────────────────────────
# Try to reuse `nexus build` auto-cache (target/nexus/nexus.wasm).
# If the cache is valid, copy it as stage0 instead of recompiling.
STAGE0="$BUILD_DIR/stage0.wasm"
NEXUS_CACHE="target/nexus/nexus.wasm"
NEXUS_CACHE_COMMIT="target/nexus/.commit"
# Reuse cache only if it was built from the current commit.
nexus_cache_valid() {
[[ -f "$NEXUS_CACHE" ]] || return 1
[[ -f "$NEXUS_CACHE_COMMIT" ]] || return 1
[[ "$(cat "$NEXUS_CACHE_COMMIT")" == "$CURRENT_COMMIT" ]] || return 1
return 0
}
if nexus_cache_valid; then
info "Stage 0: reusing cached nexus.wasm (commit ${CURRENT_COMMIT:0:7})"
cp "$NEXUS_CACHE" "$STAGE0"
else
info "Stage 0: nexus build $NEXUS_ENTRY → $STAGE0"
if [[ -f "$NEXUS_CACHE" ]]; then
cp "$NEXUS_CACHE" "$STAGE0"
mkdir -p "$(dirname "$NEXUS_CACHE_COMMIT")"
echo "$CURRENT_COMMIT" > "$NEXUS_CACHE_COMMIT"
else
"$NEXUS" build $NEXUS_BUILD_FLAGS "$NEXUS_ENTRY" -o "$STAGE0"
fi
fi
ok "Stage 0 complete: $STAGE0 ($(wc -c < "$STAGE0" | tr -d ' ') bytes)"
# ─── Stage 1: stage0.wasm compiles src → stage1.wasm ──────────────────────
# Stage0 may be a stub (no merge). If stage1 is core WASM with unresolved imports,
# compose it with stdlib. Once stage1 has the merge code, stage2+ are self-contained.
STAGE1_RAW="$BUILD_DIR/stage1_raw.wasm"
STAGE1="$BUILD_DIR/stage1.wasm"
info "Stage 1: wasmtime run $STAGE0 $NEXUS_ENTRY $STAGE1_RAW"
"$WASMTIME" run $WASMTIME_FLAGS_COMPONENT "$STAGE0" "$NEXUS_ENTRY" --verbose "$STAGE1_RAW"
# Check if stage1 is self-contained (no nexus:stdlib imports) or needs compose
if wasm-tools print "$STAGE1_RAW" 2>/dev/null | grep -q 'import "nexus:stdlib/'; then
info "Stage 1 has unresolved stdlib imports — composing..."
"$NEXUS" compose "$STAGE1_RAW" -o "$STAGE1"
ok "Stage 1 composed: $STAGE1 ($(wc -c < "$STAGE1" | tr -d ' ') bytes)"
STAGE1_FLAGS="$WASMTIME_FLAGS_COMPONENT"
else
cp "$STAGE1_RAW" "$STAGE1"
ok "Stage 1 self-contained: $STAGE1 ($(wc -c < "$STAGE1" | tr -d ' ') bytes)"
STAGE1_FLAGS="$WASMTIME_FLAGS_CORE"
fi
# ─── Stage 2: stage1.wasm compiles src → stage2.wasm ──────────────────────
STAGE2="$BUILD_DIR/stage2.wasm"
info "Stage 2: wasmtime run $STAGE1 $NEXUS_ENTRY $STAGE2"
if ! "$WASMTIME" run $STAGE1_FLAGS "$STAGE1" "$NEXUS_ENTRY" "$STAGE2" 2>&1; then
fail "Stage 2 failed — src-produced WASM is not self-executable."
fi
ok "Stage 2 complete: $STAGE2 ($(wc -c < "$STAGE2" | tr -d ' ') bytes)"
# Validate stage2 as a well-formed wasm module. wasmtime run exit 0 only means
# stage1 ran to completion; it does not check the bytes stage1 emitted.
if ! wasm-tools validate "$STAGE2" 2>&1; then
fail "Stage 2 failed validation — src produced an ill-formed wasm module."
fi
ok "Stage 2 passes wasm-tools validate"
# ─── Verify fixed point ───────────────────────────────────────────────────
info "Verifying fixed point: stage1 == stage2"
if ! cmp -s "$STAGE1" "$STAGE2"; then
S1_SIZE=$(wc -c < "$STAGE1" | tr -d ' ')
S2_SIZE=$(wc -c < "$STAGE2" | tr -d ' ')
info "stage1: $S1_SIZE bytes, stage2: $S2_SIZE bytes"
fail "Fixed point NOT reached — stage1.wasm and stage2.wasm differ."
fi
ok "Fixed point reached! stage1.wasm and stage2.wasm are identical."
ok "The self-hosted compiler is verified."
# ─── Install nexus.wasm ──────────────────────────────────────────────────
# Stage1 is already self-contained (stdlib merged). Install directly.
info "Installing nexus.wasm..."
cp "$STAGE1" nexus.wasm
ok "Installed nexus.wasm ($(wc -c < nexus.wasm | tr -d ' ') bytes)"