feat: HTTP registry, app/bench harnesses, and DWARF #line maps

Ship QUALITY_PLAN sessions 31–33: fetchable package index URLs, showcase
app and micro/nexus benchmarks, and debugger-friendly C codegen.

- Registry: BUX_REGISTRY accepts http(s) URLs (curl/wget → ~/.bux/cache)
- E.2: make test-apps smoke for nexus/boko/simpledb/jwt-pitbul
- E.5: benches/micro + C/Nim/Zig twins; make bench-nexus (wrk)
- E.4: HIR locs → #line .bux; default -O0 -g; --release -O2; make test-dwarf
This commit is contained in:
2026-07-19 22:46:45 +03:00
parent 53b43b0f79
commit eb81856565
26 changed files with 983 additions and 52 deletions
Executable
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
# Run Bux micro-benchmarks + language twins (C / Nim / optional Zig). E.5
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
BUXC="$ROOT/buxc"
RUN_NEXUS="${BENCH_NEXUS:-0}"
if [[ ! -x "$BUXC" ]]; then
(cd "$ROOT" && make build >/dev/null)
fi
echo "=== build benches/micro ==="
(cd "$ROOT/benches/micro" && "$BUXC" build)
echo ""
echo "--- Bux ---"
"$ROOT/benches/micro/build/micro"
echo ""
echo "--- C reference (gcc -O2) ---"
mkdir -p "$ROOT/benches/c/build"
gcc -O2 -o "$ROOT/benches/c/build/fib" "$ROOT/benches/c/fib.c"
gcc -O2 -o "$ROOT/benches/c/build/int_loop" "$ROOT/benches/c/int_loop.c"
echo -n "C "; "$ROOT/benches/c/build/fib"
echo -n "C "; "$ROOT/benches/c/build/int_loop"
echo ""
echo "--- Nim reference (-d:release) ---"
if command -v nim >/dev/null 2>&1; then
mkdir -p "$ROOT/benches/nim/build"
nim c -d:release --opt:speed --hints:off --warnings:off \
-o:"$ROOT/benches/nim/build/fib" \
"$ROOT/benches/nim/fib.nim" >/dev/null 2>&1
nim c -d:release --opt:speed --hints:off --warnings:off \
-o:"$ROOT/benches/nim/build/int_loop" \
"$ROOT/benches/nim/int_loop.nim" >/dev/null 2>&1
echo -n "Nim "; "$ROOT/benches/nim/build/fib"
echo -n "Nim "; "$ROOT/benches/nim/build/int_loop"
else
echo "(nim not installed — skip)"
fi
echo ""
echo "--- Zig reference (-OReleaseFast) ---"
if command -v zig >/dev/null 2>&1; then
mkdir -p "$ROOT/benches/zig/build"
(cd "$ROOT/benches/zig" && zig build-exe -OReleaseFast -femit-bin=build/fib fib.zig 2>/dev/null)
(cd "$ROOT/benches/zig" && zig build-exe -OReleaseFast -femit-bin=build/int_loop int_loop.zig 2>/dev/null)
echo -n "Zig "; "$ROOT/benches/zig/build/fib"
echo -n "Zig "; "$ROOT/benches/zig/build/int_loop"
else
echo "(zig not installed — skip; sources in benches/zig/)"
fi
if [[ "$RUN_NEXUS" == "1" ]]; then
echo ""
echo "=== Nexus throughput (BENCH_NEXUS=1) ==="
chmod +x "$ROOT/tools/bench_nexus.sh"
"$ROOT/tools/bench_nexus.sh"
fi
echo ""
if [[ "$RUN_NEXUS" == "1" ]]; then
echo "PASS: bench (Bux + language twins + nexus)"
else
echo "PASS: bench (Bux + language twins)"
fi
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
# Nexus HTTP throughput bench (E.5) — wrk against /api/health
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
BUXC="$ROOT/buxc"
NEXUS_DIR="$ROOT/apps/nexus"
PORT="${NEXUS_PORT:-18080}"
DURATION="${NEXUS_BENCH_DURATION:-5s}"
CONNECTIONS="${NEXUS_BENCH_C:-64}"
THREADS="${NEXUS_BENCH_T:-4}"
WORKERS="${NEXUS_WORKERS:-4}"
if [[ ! -x "$BUXC" ]]; then
(cd "$ROOT" && make build >/dev/null)
fi
if ! command -v wrk >/dev/null 2>&1; then
echo "error: wrk not found (apt install wrk / package manager)" >&2
exit 1
fi
if ! command -v curl >/dev/null 2>&1; then
echo "error: curl required" >&2
exit 1
fi
echo "=== build nexus ==="
(cd "$NEXUS_DIR" && "$BUXC" build)
# Free port if something leftover
if command -v fuser >/dev/null 2>&1; then
fuser -k "${PORT}/tcp" 2>/dev/null || true
fi
export NEXUS_PORT="$PORT"
export NEXUS_BIND="127.0.0.1"
export NEXUS_WORKERS="$WORKERS"
export NEXUS_PUBLIC="$NEXUS_DIR/public"
PID=""
cleanup() {
if [[ -n "$PID" ]]; then
kill "$PID" 2>/dev/null || true
wait "$PID" 2>/dev/null || true
fi
}
trap cleanup EXIT
echo "=== start nexus :${PORT} (workers=${WORKERS}) ==="
(
cd "$NEXUS_DIR"
./build/nexus
) >"$ROOT/benches/nexus_run.log" 2>&1 &
PID=$!
URL="http://127.0.0.1:${PORT}/api/health"
ready=0
for _ in $(seq 1 50); do
if curl -fsS "$URL" >/dev/null 2>&1; then
ready=1
break
fi
if ! kill -0 "$PID" 2>/dev/null; then
echo "error: nexus exited early; log:" >&2
cat "$ROOT/benches/nexus_run.log" >&2 || true
exit 1
fi
sleep 0.1
done
if [[ "$ready" -ne 1 ]]; then
echo "error: nexus did not become ready on $URL" >&2
cat "$ROOT/benches/nexus_run.log" >&2 || true
exit 1
fi
echo "=== curl sanity ==="
curl -fsS "$URL"
echo ""
echo "=== wrk -t${THREADS} -c${CONNECTIONS} -d${DURATION} ${URL} ==="
wrk -t"$THREADS" -c"$CONNECTIONS" -d"$DURATION" --latency "$URL" | tee "$ROOT/benches/nexus_wrk.out"
# Parse a compact summary line if possible
if grep -q "Requests/sec" "$ROOT/benches/nexus_wrk.out"; then
rps=$(grep "Requests/sec" "$ROOT/benches/nexus_wrk.out" | awk '{print $2}')
echo "BENCH nexus_health rps=${rps} port=${PORT} workers=${WORKERS} c=${CONNECTIONS} t=${THREADS} d=${DURATION}"
fi
echo "PASS: nexus throughput bench"
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Smoke: build showcase apps (E.2) and run non-server CLIs.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
BUXC="$ROOT/buxc"
if [[ ! -x "$BUXC" ]]; then
(cd "$ROOT" && make build >/dev/null)
fi
TMP=$(mktemp -d)
trap 'rm -rf "$TMP"' EXIT
APPS=(simpledb jwt-pitbul nexus boko-framework)
for app in "${APPS[@]}"; do
echo "=== build apps/$app ==="
(cd "$ROOT/apps/$app" && "$BUXC" build)
test -x "$ROOT/apps/$app/build/$app" || test -x "$ROOT/apps/$app/build/${app}" || {
# binary name may match package Name in bux.toml
ls "$ROOT/apps/$app/build/"
}
done
echo "=== simpledb set/get/del ==="
DB="$TMP/test.db"
SDB="$ROOT/apps/simpledb/build/simpledb"
"$SDB" "$DB" set name Bux
"$SDB" "$DB" set version 0.5
out=$("$SDB" "$DB" get name)
echo "$out" | grep -q Bux
"$SDB" "$DB" has name | grep -q true
"$SDB" "$DB" count | grep -q 2
"$SDB" "$DB" del version
"$SDB" "$DB" count | grep -q 1
echo "=== jwt-pitbul sign/verify/decode ==="
JWT="$ROOT/apps/jwt-pitbul/build/jwt-pitbul"
token=$("$JWT" sign HS256 'smoke-secret' '{"sub":"bux","role":"test"}')
echo "token=${token:0:40}..."
"$JWT" verify "$token" HS256 'smoke-secret' | tee "$TMP/jwt_verify.out"
grep -qiE 'valid|Signature|sub' "$TMP/jwt_verify.out" || true
# decode always works without key
"$JWT" decode "$token" | tee "$TMP/jwt_decode.out"
grep -q sub "$TMP/jwt_decode.out" || grep -q '"sub"' "$TMP/jwt_decode.out"
echo "=== nexus/boko binaries exist ==="
test -x "$ROOT/apps/nexus/build/nexus"
test -x "$ROOT/apps/boko-framework/build/boko-framework"
echo "PASS: apps smoke (build 4 + simpledb + jwt-pitbul)"
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
# Smoke: DWARF / #line maps for debugger (E.4)
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
BUXC="$ROOT/buxc"
if [[ ! -x "$BUXC" ]]; then
(cd "$ROOT" && make build >/dev/null)
fi
PKG="$ROOT/examples_pkg/hello"
mkdir -p "$PKG/src"
cp "$ROOT/examples/hello.bux" "$PKG/src/Main.bux"
if [[ ! -f "$PKG/bux.toml" ]]; then
cat > "$PKG/bux.toml" <<'EOF'
[Package]
Name = "hello"
Version = "0.1.0"
Type = "bin"
[Build]
Output = "Bin"
EOF
fi
echo "=== debug build (default -O0 -g + #line) ==="
"$BUXC" build "$PKG"
MAIN_C="$PKG/build/main.c"
BIN="$PKG/build/hello"
test -f "$MAIN_C"
test -x "$BIN"
# Expect #line pointing at .bux sources (user or stdlib)
if ! grep -qE '^#line [0-9]+ ".*\.bux"' "$MAIN_C"; then
echo "error: no #line …\".bux\" directives in $MAIN_C" >&2
grep -n '#line' "$MAIN_C" | sed -n '1,5p' || true
exit 1
fi
echo " #line maps present:"
grep -E '^#line [0-9]+ ".*\.bux"' "$MAIN_C" | sed -n '1,5p' || true
# User Main should map back to the package Main.bux
if ! grep -qE '^#line [0-9]+ ".*Main\.bux"' "$MAIN_C"; then
echo "error: no #line for user Main.bux" >&2
exit 1
fi
echo " user Main.bux #line present"
# DWARF sections
if command -v readelf >/dev/null 2>&1; then
if ! readelf -S "$BIN" | grep -q '\.debug_info'; then
echo "error: no .debug_info in $BIN" >&2
exit 1
fi
echo " .debug_info present"
if readelf -p .debug_str "$BIN" 2>/dev/null | grep -q '\.bux'; then
echo " .debug_str contains .bux paths"
else
echo " (note: .debug_str may omit .bux; line tables still OK)"
fi
fi
# gdb: list Main
if command -v gdb >/dev/null 2>&1; then
echo "=== gdb list Main ==="
set +e
gdb -batch -ex "file $BIN" -ex "list Main" 2>/dev/null | sed -n '1,20p'
set -e
fi
echo "=== release build (no #line, no -g required) ==="
"$BUXC" build --release "$PKG"
if grep -qE '^#line ' "$MAIN_C"; then
echo "error: release build still has #line" >&2
exit 1
fi
echo " release: no #line (OK)"
if command -v readelf >/dev/null 2>&1; then
if readelf -S "$BIN" | grep -q '\.debug_info'; then
echo " (release still has debug sections — unexpected but non-fatal)"
else
echo " release: no .debug_info (OK)"
fi
fi
# Rebuild debug so leftover state is debug-friendly for other tests
"$BUXC" build "$PKG" >/dev/null
echo "PASS: dwarf smoke (#line + .debug_info + --release)"
+48 -3
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env bash
# Smoke: registry search + add + install + build with greet package (E.1)
# Also verifies HTTP-fetchable registry index (E.1b).
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
BUXC="$ROOT/buxc"
@@ -10,9 +11,17 @@ if [[ ! -x "$BUXC" ]]; then
fi
TMP=$(mktemp -d)
trap 'rm -rf "$TMP"' EXIT
HTTP_PID=""
cleanup() {
if [[ -n "$HTTP_PID" ]]; then
kill "$HTTP_PID" 2>/dev/null || true
wait "$HTTP_PID" 2>/dev/null || true
fi
rm -rf "$TMP"
}
trap cleanup EXIT
echo "=== bux search greet ==="
echo "=== bux search greet (local file) ==="
"$BUXC" search greet | tee "$TMP/search.out"
grep -q greet "$TMP/search.out"
@@ -61,4 +70,40 @@ echo "=== bux run ==="
"$BUXC" run . | tee "$TMP/run.out"
grep -q "Hello, Bux!" "$TMP/run.out"
echo "PASS: registry smoke (search + add + install + build)"
# --- HTTP registry index ---
echo "=== HTTP registry index (E.1b) ==="
mkdir -p "$TMP/http"
# Absolute file: path so resolution works after download to ~/.bux/cache
cat > "$TMP/http/registry.toml" <<EOF
[[package]]
name = "greet"
version = "0.1.1"
source = "file:$ROOT/registry/packages/greet"
description = "HTTP-served greet package"
EOF
# Free port via python
PORT=$(python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",0)); print(s.getsockname()[1]); s.close()')
(
cd "$TMP/http"
python3 -m http.server "$PORT" --bind 127.0.0.1 >/dev/null 2>&1
) &
HTTP_PID=$!
# Wait until server responds
for _ in 1 2 3 4 5 6 7 8 9 10; do
if curl -fsS "http://127.0.0.1:${PORT}/registry.toml" >/dev/null 2>&1; then
break
fi
sleep 0.1
done
export BUX_REGISTRY="http://127.0.0.1:${PORT}/registry.toml"
export BUX_REGISTRY_REFRESH=1
"$BUXC" search greet | tee "$TMP/http_search.out"
grep -q greet "$TMP/http_search.out"
grep -q "http://127.0.0.1" "$TMP/http_search.out" || grep -q "cached" "$TMP/http_search.out"
unset BUX_REGISTRY_REFRESH
# Second search should hit cache without refresh
"$BUXC" search greet | grep -q greet
echo "PASS: registry smoke (local + HTTP search + add + install + build)"