diff options
| author | eunhhu <[email protected]> | 2026-09-24 17:14:54 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-24 17:14:54 +0100 |
| commit | b1ce1927022d374198441afafeb27199fc8a052a (patch) | |
| tree | 6021f175f4c67ed03b44240eaa2f90d846f12f6f /prototypes/live-rules/manage.py | |
| parent | d34f9426d5317a1948f12f229439946728bc342a (diff) | |
| download | pure-b1ce1927022d374198441afafeb27199fc8a052a.tar.gz pure-b1ce1927022d374198441afafeb27199fc8a052a.zip | |
Establish native micro runtime checkpoint
Diffstat (limited to 'prototypes/live-rules/manage.py')
| -rw-r--r-- | prototypes/live-rules/manage.py | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/prototypes/live-rules/manage.py b/prototypes/live-rules/manage.py new file mode 100644 index 0000000..fbe047c --- /dev/null +++ b/prototypes/live-rules/manage.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +"""Build/test the shared Zig core or serve the local experiment. No Python dependencies.""" +import argparse +from datetime import datetime, timezone +from functools import partial +import hashlib +from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer +import json +from pathlib import Path +import shutil +import subprocess + +ROOT = Path(__file__).resolve().parent +VERSION = "0.15.2" + + +def digest(path): + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def build(zig): + compiler = shutil.which(zig) + if compiler is None: + raise SystemExit("Zig 0.15.2가 필요합니다. ziglang.org/download 또는 --zig /path/to/zig를 사용하세요.") + version = subprocess.check_output([compiler, "version"], text=True).strip() + if version != VERSION: + raise SystemExit(f"이 실험은 Zig {VERSION}로 고정했습니다. 현재: {version}") + build_dir = ROOT / "build" + build_dir.mkdir(exist_ok=True) + cache = ["--cache-dir", str(build_dir / "cache"), + "--global-cache-dir", str(build_dir / "global-cache")] + source = ROOT / "core.zig" + native = [compiler, "test", str(source), *cache] + print("Checking native core…", flush=True) + checked = subprocess.run(native, capture_output=True, text=True) + print(checked.stdout + checked.stderr, end="", flush=True) + checked.check_returncode() + wasm = ROOT / "web" / "core.wasm" + wasm.parent.mkdir(exist_ok=True) + flags = ["-target", "wasm32-freestanding", "-O", "ReleaseSafe", "-fno-entry", + "-rdynamic", "--export-memory", "--stack", "16384", + "--initial-memory=65536", "--max-memory=65536"] + command = [compiler, "build-exe", str(source), *flags, f"-femit-bin={wasm}", *cache] + subprocess.run(command, check=True) + (build_dir / "build.json").write_text(json.dumps({ + "built_utc": datetime.now(timezone.utc).isoformat(), + "zig_version": version, "flags": flags, + "source_sha256": digest(source), "wasm_sha256": digest(wasm), + "wasm_file_bytes": wasm.stat().st_size, + "native_test_output": checked.stdout + checked.stderr, + }, ensure_ascii=False, indent=2) + "\n") + print(f"Built {wasm} ({wasm.stat().st_size:,} bytes)") + + +class Handler(SimpleHTTPRequestHandler): + extensions_map = {**SimpleHTTPRequestHandler.extensions_map, ".wasm": "application/wasm"} + + def end_headers(self): + self.send_header("Cache-Control", "no-store") + super().end_headers() + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + sub = parser.add_subparsers(dest="action", required=True) + compile_cmd = sub.add_parser("build", help="native tests + WebAssembly build") + compile_cmd.add_argument("--zig", default="zig") + serve = sub.add_parser("serve", help="serve web/ on loopback only") + serve.add_argument("--port", type=int, default=8765) + args = parser.parse_args() + if args.action == "build": + build(args.zig) + return + if not 1 <= args.port <= 65535: + parser.error("port must be between 1 and 65535") + if not (ROOT / "web" / "core.wasm").is_file(): + parser.error("먼저 manage.py build를 실행하세요.") + handler = partial(Handler, directory=str(ROOT / "web")) + with ThreadingHTTPServer(("127.0.0.1", args.port), handler) as server: + print(f"Pure: http://127.0.0.1:{args.port} (Ctrl+C to stop)", flush=True) + try: + server.serve_forever() + except KeyboardInterrupt: + pass + + +if __name__ == "__main__": + main() |
