#!/usr/bin/env python3 """Build and validate the bounded Factorio RNG no-JIT prototype on Apple Silicon.""" import argparse import json import subprocess from pathlib import Path from lift_rng import generate ROOT = Path(__file__).resolve().parent.parent def run(*command): print("+", " ".join(map(str, command)), flush=True) subprocess.run(list(map(str, command)), cwd=ROOT, check=True) def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("binary", type=Path) args = parser.parse_args() wabt = ROOT / "third_party/wabt" if not (wabt / "CMakeLists.txt").exists(): parser.error("Fetch official WABT tag 1.0.42 into third_party/wabt first") revision = subprocess.check_output(["git", "-C", str(wabt), "rev-parse", "HEAD"], text=True).strip() if revision != "ff0ef7e0009402740c805a9744c09b05be063e48": parser.error("WABT checkout must match the pinned 1.0.42 commit") run("cmake", "-S", wabt, "-B", ROOT / "build/wabt", "-DCMAKE_BUILD_TYPE=Release", "-DBUILD_TESTS=OFF", "-DBUILD_LIBWASM=OFF", "-DUSE_INTERNAL_SHA256=ON", "-DHAVE_OPENSSL_SHA_H=OFF") run("cmake", "--build", ROOT / "build/wabt", "--target", "wat2wasm", "wasm2c", "--parallel", "6") out = ROOT / "build/rng" generate(args.binary.resolve(), out) run(ROOT / "build/wabt/wat2wasm", out / "factorio_rng.wat", "-o", out / "factorio_rng.wasm") run(ROOT / "build/wabt/wasm2c", out / "factorio_rng.wasm", "-o", out / "factorio_rng.c", "--module-name=factorio_rng") sources = [out / "factorio_rng.c", wabt / "wasm2c/wasm-rt-impl.c", wabt / "wasm2c/wasm-rt-mem-impl.c"] includes = ["-I" + str(out), "-I" + str(wabt / "wasm2c")] flags = ["-O2", "-DWASM_RT_USE_MMAP=0", "-DWASM_RT_MEMCHECK_BOUNDS_CHECK=1"] run("xcrun", "clang", *flags, *includes, *sources, out / "oracle.S", ROOT / "tests/rng_equivalence.c", "-o", out / "verify_rng") run(out / "verify_rng") # This archive contains the translated function and wasm2c runtime only. # The native oracle is a desktop verification input, never iOS runtime code. objects = [] sdk = subprocess.check_output(["xcrun", "--sdk", "iphoneos", "--show-sdk-path"], text=True).strip() for source in sources: obj = out / (source.stem + ".ios.o") run("xcrun", "--sdk", "iphoneos", "clang", "-target", "arm64-apple-ios15.0", "-isysroot", sdk, *flags, *includes, "-c", source, "-o", obj) objects.append(obj) run("xcrun", "libtool", "-static", "-o", out / "libfactorio_rng_ios.a", *objects) undefined = subprocess.check_output(["xcrun", "nm", "-u", str(out / "libfactorio_rng_ios.a")], text=True) if "steam" in undefined.lower(): raise RuntimeError("Steam import found in the single-player port library") report = {"status": "pass", "native_comparisons": 876544, "constructor_comparisons": 1024, "starting_states": 6848, "steps_per_state": 128, "ios_artifact": "libfactorio_rng_ios.a", "ios_device_execution": "not run", "full_game": "not implemented", "wabt_commit": revision, "runtime_jit": False, "steam_import_audit": "pass: no Steam undefined symbols"} (out / "verification.json").write_text(json.dumps(report, indent=2) + "\n") if __name__ == "__main__": main()