From 34a77892c900c9ddad412f88e8b0ebaa3c82fd3f Mon Sep 17 00:00:00 2001 From: grabowski Date: Thu, 22 Oct 2026 17:21:51 +0700 Subject: [PATCH] build_web: use rustup's cargo even when another Rust comes first on PATH A standalone "Rust stable GNU" install ahead of ~/.cargo/bin made cargo fail with E0463 (no wasm32 std). The script now puts CARGO_HOME/bin first, checks for rustup and the wasm32 target, and says what to install. --- tools/build_web.py | 62 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/tools/build_web.py b/tools/build_web.py index 7097dbe..46e7dfb 100644 --- a/tools/build_web.py +++ b/tools/build_web.py @@ -2,10 +2,11 @@ python tools/build_web.py [--out dist/web] [--skip-cargo] -Needs the wasm32-unknown-unknown target (rustup target add wasm32-unknown-unknown) -and the wasm-bindgen CLI at the version in Cargo.lock. wasm-opt (binaryen) is -used when it is on PATH. The output folder is static files: serve it from any -web server (it needs http(s), not file://). +Needs rustup with the wasm32-unknown-unknown target (rustup target add +wasm32-unknown-unknown) and the wasm-bindgen CLI at the version in Cargo.lock. +rustup's cargo is used even when another Rust install comes first on PATH. +wasm-opt (binaryen) is used when it is on PATH. The output folder is static +files: serve it from any web server (it needs http(s), not file://). """ import argparse import hashlib @@ -19,11 +20,44 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent SKIP_DIRS = {"dist", "target", "node_modules"} +TARGET = "wasm32-unknown-unknown" + +# rustup's bin folder first: a standalone Rust install earlier on PATH (one +# without the wasm target, e.g. "Rust stable GNU") must not win +CARGO_BIN = Path(os.environ.get("CARGO_HOME") or Path.home() / ".cargo") / "bin" +ENV = dict(os.environ) +if CARGO_BIN.is_dir(): + ENV["PATH"] = str(CARGO_BIN) + os.pathsep + ENV.get("PATH", "") + + +def tool(name): + return shutil.which(name, path=ENV["PATH"]) def run(cmd, **kw): print("+", " ".join(str(c) for c in cmd), flush=True) - subprocess.run([str(c) for c in cmd], check=True, cwd=ROOT, **kw) + subprocess.run([str(c) for c in cmd], check=True, cwd=ROOT, env=ENV, **kw) + + +def check_toolchain(): + """rustup with the wasm target, and wasm-bindgen at the locked version.""" + rustup = tool("rustup") + if not rustup: + sys.exit("rustup not found (https://rustup.rs): the WASM build needs rustup's toolchain") + installed = subprocess.run([rustup, "target", "list", "--installed"], capture_output=True, text=True, + cwd=ROOT, env=ENV).stdout.split() + if TARGET not in installed: + sys.exit(f"the {TARGET} target is not installed: rustup target add {TARGET}") + cargo = tool("cargo") + if not cargo or Path(cargo).parent.resolve() != CARGO_BIN.resolve(): + sys.exit(f"cargo resolves to {cargo}, not rustup's in {CARGO_BIN}") + want = lock_version("wasm-bindgen") + exe = tool("wasm-bindgen") + if not exe: + sys.exit(f"wasm-bindgen CLI not found: cargo install wasm-bindgen-cli --version {want}") + have = subprocess.run([exe, "--version"], capture_output=True, text=True, env=ENV).stdout.split()[-1] + if have != want: + sys.exit(f"wasm-bindgen CLI is {have}, Cargo.lock has {want}: cargo install wasm-bindgen-cli --version {want}") def lock_version(name): @@ -63,25 +97,21 @@ def main(): wasm = ROOT / "target" / "wasm32-unknown-unknown" / "web" / "isokit_wasm.wasm" if not a.skip_cargo: - want = lock_version("wasm-bindgen") - try: - have = subprocess.run(["wasm-bindgen", "--version"], capture_output=True, text=True, check=True).stdout.split()[-1] - except (OSError, subprocess.CalledProcessError): - sys.exit(f"wasm-bindgen CLI not found: cargo install wasm-bindgen-cli --version {want}") - if have != want: - sys.exit(f"wasm-bindgen CLI is {have}, Cargo.lock has {want}: cargo install wasm-bindgen-cli --version {want}") - run(["cargo", "build", "-p", "isokit-wasm", "--target", "wasm32-unknown-unknown", "--profile", "web"]) + check_toolchain() + run([tool("cargo"), "build", "-p", "isokit-wasm", "--target", TARGET, "--profile", "web"]) + elif not tool("wasm-bindgen"): + sys.exit("wasm-bindgen CLI not found") if out.exists(): shutil.rmtree(out) web.mkdir(parents=True) if not wasm.exists(): sys.exit(f"{wasm} missing: run without --skip-cargo") - run(["wasm-bindgen", "--target", "web", "--no-typescript", "--remove-name-section", + run([tool("wasm-bindgen"), "--target", "web", "--no-typescript", "--remove-name-section", "--remove-producers-section", "--out-dir", web.as_posix(), wasm.as_posix()]) bg = web / "isokit_wasm_bg.wasm" - if shutil.which("wasm-opt"): - run(["wasm-opt", "-Oz", "--all-features", bg.as_posix(), "-o", bg.as_posix()]) + if tool("wasm-opt"): + run([tool("wasm-opt"), "-Oz", "--all-features", bg.as_posix(), "-o", bg.as_posix()]) else: print(" (wasm-opt not found: the .wasm stays unoptimised by binaryen, about 15% larger)")