Files
hakorune/tools/selfhost/selfhost_build.sh
nyash-codex 804ccff23f feat(phase73): Selfhost Stage-B I/O 簡素化 - HAKO_SRC 環境変数統一化
Unified selfhost Stage-B I/O path from argv to environment variables:
- Remove --source "$SRC_CONTENT" from compiler.hako invocation (argv limit)
- Export HAKO_SRC="$SRC_CONTENT" instead (env-based I/O)
- Update compiler_stageb.hako to check HAKO_SRC fallback

Changes:
1. lang/src/compiler/entry/compiler_stageb.hako:
   - Added HAKO_SRC env check in StageBArgsBox.resolve_src()
   - Fallback order: --source arg → HAKO_SOURCE_FILE_CONTENT → HAKO_SRC → default

2. tools/selfhost/selfhost_build.sh:
   - Removed --source "$SRC_CONTENT" from compiler.hako invocation
   - Export HAKO_SRC="$SRC_CONTENT" before Stage-B execution
   - Unified with wrapper pathway (HAKO_USE_BUILDBOX=1)

Benefits:
- Eliminates "Argument list too long" (os error 7) for large .hako files
- Single unified I/O pattern (env variables) for all Stage-B paths
- Consistent with hako_check.sh and wrapper pattern
- Ready for future HAKO_SRC_FILE optimization

Verification:
 NYASH_FEATURES=stage3 NYASH_USE_NY_COMPILER=1 \
  ./tools/selfhost/selfhost_build.sh --in apps/tests/stage1_run_min.hako --run
  Output: abc (correct)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 13:09:10 +09:00

188 lines
6.2 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# selfhost_build.sh — Hybrid selfhost build (StageB → Program(JSON v0) → optional run via CoreDirect)
#
# Goals (80/20):
# - Take a Hako source (.hako), compile with Hakorune StageB to Program(JSON v0).
# - Optionally run via GateC/Core Direct (inproc) to verify exit code.
# - (Future) Optionally convert to MIR and build an executable via ny-llvmc.
#
# Usage:
# tools/selfhost/selfhost_build.sh --in source.hako [--json out.json] [--run]
# Env:
# NYASH_BIN: path to hakorune/nyash binary (auto-detected if omitted)
# NYASH_ROOT: repo root (auto-detected)
#
set -euo pipefail
ROOT="${NYASH_ROOT:-$(cd "$(dirname "$0")/../.." && pwd)}"
BIN="${NYASH_BIN:-}"
if [ -z "${BIN}" ]; then
if [ -x "$ROOT/target/release/hakorune" ]; then BIN="$ROOT/target/release/hakorune";
elif [ -x "$ROOT/target/release/nyash" ]; then BIN="$ROOT/target/release/nyash";
else echo "[selfhost] error: NYASH_BIN not set and no binary found under target/release" >&2; exit 2; fi
fi
RAW_KEEP="${NYASH_SELFHOST_KEEP_RAW:-0}"
RAW_DIR="${NYASH_SELFHOST_RAW_DIR:-$ROOT/logs/selfhost}"
if [ "$RAW_KEEP" = "1" ]; then
mkdir -p "$RAW_DIR" 2>/dev/null || RAW_KEEP=0
fi
timestamp_now() { date +%Y%m%d_%H%M%S; }
IN=""
JSON_OUT=""
MIR_OUT=""
EXE_OUT=""
DO_RUN=0
KEEP_TMP=0
apply_selfhost_env() {
export NYASH_FEATURES="${NYASH_FEATURES:-stage3}"
export NYASH_PARSER_ALLOW_SEMICOLON=1
export NYASH_ALLOW_USING_FILE=0
export HAKO_ALLOW_USING_FILE=0
export NYASH_USING_AST=1
export NYASH_VARMAP_GUARD_STRICT=0
export NYASH_BLOCK_SCHEDULE_VERIFY=0
export NYASH_QUIET=0 HAKO_QUIET=0 NYASH_CLI_VERBOSE=0
# Ensure core plugins (Console/Array/Map/String/Integer) are discoverable
export NYASH_PLUGIN_PATH="${NYASH_PLUGIN_PATH:-$ROOT/target/release}"
export NYASH_PLUGIN_PATHS="${NYASH_PLUGIN_PATHS:-$NYASH_PLUGIN_PATH}"
}
while [ $# -gt 0 ]; do
case "$1" in
--in) IN="$2"; shift 2;;
--json) JSON_OUT="$2"; shift 2;;
--run) DO_RUN=1; shift;;
--mir) MIR_OUT="$2"; shift 2;;
--keep-tmp) KEEP_TMP=1; shift;;
--exe) EXE_OUT="$2"; shift 2;;
*) echo "[selfhost] unknown arg: $1" >&2; exit 2;;
esac
done
if [ -z "$IN" ]; then echo "[selfhost] --in <file.hako> is required" >&2; exit 2; fi
if [ ! -f "$IN" ]; then echo "[selfhost] input not found: $IN" >&2; exit 2; fi
tmp_json="${JSON_OUT:-/tmp/hako_stageb_$$.json}"
# Emit Program(JSON v0; prefer BuildBox for emit-only when HAKO_USE_BUILDBOX=1)
RAW="/tmp/hako_stageb_raw_$$.txt"
stageb_rc=0
SRC_CONTENT="$(cat "$IN")"
stageb_cmd_desc=""
if [ "${HAKO_USE_BUILDBOX:-0}" = "1" ] && [ "$DO_RUN" = "0" ] && [ -z "$EXE_OUT" ]; then
apply_selfhost_env
stageb_cmd_desc="BuildBox.emit_program_json_v0 via compiler build_box"
WRAP="/tmp/hako_buildbox_wrap_$$.hako"
cat > "$WRAP" <<'HAKO'
include "lang/src/compiler/build/build_box.hako"
static box Main { method main(args) {
local src = env.get("HAKO_SRC");
local j = BuildBox.emit_program_json_v0(src, null);
print(j);
return 0;
} }
HAKO
(
export HAKO_SRC="$SRC_CONTENT"
cd "$ROOT" && "$BIN" --backend vm "$WRAP"
) > "$RAW" 2>&1 || stageb_rc=$?
rm -f "$WRAP" 2>/dev/null || true
else
apply_selfhost_env
stageb_cmd_desc="compiler.hako --stage-b --stage3"
(
export HAKO_SRC="$SRC_CONTENT"
cd "$ROOT" && \
"$BIN" --backend vm \
"$ROOT/lang/src/compiler/entry/compiler.hako" -- \
--stage-b --stage3
) > "$RAW" 2>&1 || stageb_rc=$?
fi
extract_ok=0
if awk '(/"version":0/ && /"kind":"Program"/){print;found=1;exit} END{exit(found?0:1)}' "$RAW" > "$tmp_json"; then
extract_ok=1
fi
if [ "$RAW_KEEP" = "1" ]; then
ts="$(timestamp_now)"
raw_log="$RAW_DIR/stageb_${ts}_$$.log"
{
echo "[selfhost/raw] cmd: ${stageb_cmd_desc:-unknown}"
echo "[selfhost/raw] rc_stageb=${stageb_rc} extract_ok=${extract_ok}"
echo "[selfhost/raw] src=${IN}"
echo "[selfhost/raw] --- stdout+stderr ---"
cat "$RAW"
} > "$raw_log" 2>/dev/null || true
if [ "$extract_ok" = "1" ] && [ -s "$tmp_json" ]; then
cp "$tmp_json" "$RAW_DIR/stageb_${ts}_$$.json" 2>/dev/null || true
fi
fi
if [ "$extract_ok" != "1" ]; then
echo "[selfhost] StageB emit failed" >&2
tail -n 120 "$RAW" >&2 || true
if [ "$RAW_KEEP" = "1" ] && [ -n "${raw_log:-}" ]; then
echo "[selfhost/debug] RAW log: $raw_log" >&2
fi
if [ "$KEEP_TMP" != "1" ]; then rm -f "$RAW" 2>/dev/null || true; fi
exit 1
fi
rm -f "$RAW" 2>/dev/null || true
if [ -n "$JSON_OUT" ]; then
echo "[selfhost] JSON v0 written: $tmp_json" >&2
fi
# Optional: emit MIR(JSON) from source (runner compiles .hako directly; StageB JSON is for reference)
if [ -n "$MIR_OUT" ]; then
echo "[selfhost] emitting MIR JSON → $MIR_OUT" >&2
"$BIN" --backend mir --emit-mir-json "$MIR_OUT" "$IN" >/dev/null
fi
# Optional: build native EXE via ny-llvmc harness (fallback path; parses original source)
if [ -n "$EXE_OUT" ]; then
# Requirements: ny-llvmc present and harness envs
NYLL="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}"
if [ ! -x "$NYLL" ] && [ ! -f "$NYLL" ]; then
echo "[selfhost] ny-llvmc not found: $NYLL (Set NYASH_NY_LLVM_COMPILER or build ny-llvmc)" >&2
exit 2
fi
NYRT_DIR="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}"
export NYASH_LLVM_USE_HARNESS=1
export NYASH_NY_LLVM_COMPILER="$NYLL"
export NYASH_EMIT_EXE_NYRT="$NYRT_DIR"
# Convert Program(JSON v0) → MIR(JSON) via runner
MIR_TMP="${MIR_OUT:-/tmp/hako_stageb_mir_$$.json}"
echo "[selfhost] converting Program(JSON v0) → MIR(JSON) → EXE" >&2
"$BIN" --json-file "$tmp_json" --program-json-to-mir "$MIR_TMP"
# Build EXE via ny-llvmc
"$NYLL" --in "$MIR_TMP" --emit exe --nyrt "$NYRT_DIR" --out "$EXE_OUT"
# Cleanup
if [ "$KEEP_TMP" != "1" ]; then
if [ -z "$JSON_OUT" ]; then rm -f "$tmp_json" 2>/dev/null || true; fi
if [ -z "$MIR_OUT" ]; then rm -f "$MIR_TMP" 2>/dev/null || true; fi
fi
exit 0
fi
if [ "$DO_RUN" = "1" ]; then
# Run via CoreDirect (inproc), quiet
set +e
NYASH_GATE_C_CORE=1 HAKO_GATE_C_CORE=1 HAKO_CORE_DIRECT=1 HAKO_CORE_DIRECT_INPROC=1 \
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 NYASH_NYRT_SILENT_RESULT=1 \
"$BIN" --json-file "$tmp_json" >/dev/null 2>&1
rc=$?
set -e
if [ "$KEEP_TMP" != "1" ] && [ -z "$JSON_OUT" ]; then rm -f "$tmp_json" 2>/dev/null || true; fi
exit $rc
else
# Emit-only
echo "$tmp_json"
fi