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.
This commit is contained in:
grabowski committed 2026-10-22 17:21:51 +07:00
1 parent 5eb60d2a0c
commit 34a77892c9
1 file changed
+46 -16
+46 -16
View File
@@ -2,10 +2,11 @@
python tools/build_web.py [--out dist/web] [--skip-cargo] python tools/build_web.py [--out dist/web] [--skip-cargo]
Needs the wasm32-unknown-unknown target (rustup target add wasm32-unknown-unknown) Needs rustup with the wasm32-unknown-unknown target (rustup target add
and the wasm-bindgen CLI at the version in Cargo.lock. wasm-opt (binaryen) is wasm32-unknown-unknown) and the wasm-bindgen CLI at the version in Cargo.lock.
used when it is on PATH. The output folder is static files: serve it from any rustup's cargo is used even when another Rust install comes first on PATH.
web server (it needs http(s), not file://). 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 argparse
import hashlib import hashlib
@@ -19,11 +20,44 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent ROOT = Path(__file__).resolve().parent.parent
SKIP_DIRS = {"dist", "target", "node_modules"} 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): def run(cmd, **kw):
print("+", " ".join(str(c) for c in cmd), flush=True) 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): def lock_version(name):
@@ -63,25 +97,21 @@ def main():
wasm = ROOT / "target" / "wasm32-unknown-unknown" / "web" / "isokit_wasm.wasm" wasm = ROOT / "target" / "wasm32-unknown-unknown" / "web" / "isokit_wasm.wasm"
if not a.skip_cargo: if not a.skip_cargo:
want = lock_version("wasm-bindgen") check_toolchain()
try: run([tool("cargo"), "build", "-p", "isokit-wasm", "--target", TARGET, "--profile", "web"])
have = subprocess.run(["wasm-bindgen", "--version"], capture_output=True, text=True, check=True).stdout.split()[-1] elif not tool("wasm-bindgen"):
except (OSError, subprocess.CalledProcessError): sys.exit("wasm-bindgen CLI not found")
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"])
if out.exists(): if out.exists():
shutil.rmtree(out) shutil.rmtree(out)
web.mkdir(parents=True) web.mkdir(parents=True)
if not wasm.exists(): if not wasm.exists():
sys.exit(f"{wasm} missing: run without --skip-cargo") 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()]) "--remove-producers-section", "--out-dir", web.as_posix(), wasm.as_posix()])
bg = web / "isokit_wasm_bg.wasm" bg = web / "isokit_wasm_bg.wasm"
if shutil.which("wasm-opt"): if tool("wasm-opt"):
run(["wasm-opt", "-Oz", "--all-features", bg.as_posix(), "-o", bg.as_posix()]) run([tool("wasm-opt"), "-Oz", "--all-features", bg.as_posix(), "-o", bg.as_posix()])
else: else:
print(" (wasm-opt not found: the .wasm stays unoptimised by binaryen, about 15% larger)") print(" (wasm-opt not found: the .wasm stays unoptimised by binaryen, about 15% larger)")