#!/usr/bin/env bash # Installs every bakeoff toolchain under $HOME (no sudo), idempotently. # scripts/toolchains.sh [section...] sections: base qemu zig rust swift ocaml haskell nim spinel arm64root # Then `source scripts/env.sh` puts them on PATH. Versions land in docs/toolchains.md. set -euo pipefail export PIXI_NO_TELEMETRY=1 here=$(cd "$(dirname "$0")" && pwd) TC=${BAKEOFF_TOOLCHAINS:-$HOME/.local/share/bakeoff-toolchains} mkdir -p "$TC" "$HOME/.local/bin" dl=$(mktemp -d -p "${TMPDIR:-$HOME/.cache}") trap 'rm -rf "$dl"' EXIT source "$here/env.sh" have() { command -v "$1" >/dev/null 2>&1; } sec_base() { # pixi, plus conda-forge packages for headers and tools Debian lacks here have pixi || curl -fsSL https://pixi.sh/install.sh | PIXI_NO_PATH_UPDATE=1 bash pixi global install --environment bakeoff-base sqlite unzip pkg-config ruby gmp libffi yaml } sec_qemu() { # user-mode arm64 emulator and proot, run explicitly (no binfmt, no root) if ! [ -x "$TC/qemu/qemu-aarch64-static" ]; then # Debian 13's qemu-user ships statically linked binaries (qemu-user-static is transitional) (cd "$dl" && apt-get download qemu-user >/dev/null) dpkg-deb -x "$dl"/qemu-user_*.deb "$dl/q" mkdir -p "$TC/qemu" cp "$dl/q/usr/bin/qemu-aarch64" "$TC/qemu/qemu-aarch64-static" fi ln -sf "$TC/qemu/qemu-aarch64-static" "$HOME/.local/bin/qemu-aarch64-static" if ! [ -x "$TC/proot/proot" ]; then mkdir -p "$TC/proot" curl -fsSL -o "$TC/proot/proot" https://proot.gitlab.io/proot/bin/proot chmod +x "$TC/proot/proot" fi ln -sf "$TC/proot/proot" "$HOME/.local/bin/proot" } sec_zig() { if ! [ -x "$TC/zig/zig" ]; then url=$(curl -fsSL https://ziglang.org/download/index.json | python3 -c 'import json,sys; d=json.load(sys.stdin); v=[k for k in d if k!="master"]; v.sort(key=lambda s:[int(x) for x in s.split(".")]); print(d[v[-1]]["x86_64-linux"]["tarball"])') curl -fsSL "$url" | tar -xJ -C "$dl" rm -rf "$TC/zig" && mv "$dl"/zig-* "$TC/zig" fi ln -sf "$TC/zig/zig" "$HOME/.local/bin/zig" } sec_rust() { have rustup || curl -fsSL https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal rustup toolchain install stable --profile minimal rustup target add aarch64-unknown-linux-musl x86_64-unknown-linux-musl have cargo-zigbuild || cargo install --locked cargo-zigbuild } sec_swift() { # Swift 6.2 is installed; add the Static Linux SDK (musl, x86_64 + aarch64) swift sdk list 2>/dev/null | grep -q static-linux && return v=$(swift --version 2>&1 | sed -n 's/.*Swift version \([0-9.]*\).*/\1/p') idx=$(curl -fsSL "https://www.swift.org/api/v1/install/releases.json") read -r url sum < <(python3 -c ' import json,sys; v=sys.argv[1]; d=json.loads(sys.argv[2]) r=[x for x in d if x["name"]==v][0] s=[p for p in r["platforms"] if p.get("platform")=="static-sdk" or p.get("name","").lower().startswith("static")][0] print("https://download.swift.org/swift-%s-release/static-sdk/swift-%s-RELEASE/swift-%s-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz"%(v,v,v), s["checksum"])' "$v" "$idx") swift sdk install "$url" --checksum "$sum" } sec_ocaml() { # opam + OCaml 5 for x86-64; arm64 builds run in the arm64 root (see arm64root) if ! have opam; then curl -fsSL -o "$HOME/.local/bin/opam" "$(curl -fsSL https://api.github.com/repos/ocaml/opam/releases/latest | python3 -c 'import json,sys; print([a["browser_download_url"] for a in json.load(sys.stdin)["assets"] if a["name"].endswith("x86_64-linux")][0])')" chmod +x "$HOME/.local/bin/opam" fi [ -d "$HOME/.opam" ] || opam init --bare -n --disable-sandboxing opam switch list -s | grep -qx bakeoff || opam switch create bakeoff ocaml-base-compiler.5.3.0 -y opam install --switch bakeoff -y dune } sec_haskell() { # ghcup + recommended GHC and cabal for x86-64 if ! [ -x "$HOME/.ghcup/bin/ghcup" ]; then curl -fsSL https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh fi ghcup install ghc recommended --set ghcup install cabal recommended --set } sec_mojo() { # Mojo through pixi, as a global environment pixi global install --environment mojo -c https://conda.modular.com/max -c conda-forge mojo } sec_nim() { # Nim (prebuilt x86-64 release); arm64 via zig cc as the C compiler if ! [ -x "$TC/nim/bin/nim" ]; then v=$(curl -fsSL https://nim-lang.org/channels/stable | head -1) curl -fsSL "https://nim-lang.org/download/nim-$v-linux_x64.tar.xz" | tar -xJ -C "$dl" rm -rf "$TC/nim" && mv "$dl/nim-$v" "$TC/nim" fi for b in nim nimble; do ln -sf "$TC/nim/bin/$b" "$HOME/.local/bin/$b"; done } sec_spinel() { # spinel + tep + spinelkit at the pins lpay uses (paulca/lpay spinel/) src="$TC/spinel-src"; mkdir -p "$src" [ -d "$src/lpay" ] || gh repo clone paulca/lpay "$src/lpay" -- --depth 1 [ -d "$src/tep" ] || git clone https://github.com/OriPekelman/tep "$src/tep" [ -d "$src/spinelkit" ] || git clone https://github.com/OriPekelman/spinelkit "$src/spinelkit" [ -d "$src/spinel" ] || git clone https://github.com/matz/spinel "$src/spinel" pin=$(head -1 "$src/tep/SPINEL_PIN") (cd "$src/spinel" && git fetch -q origin && git checkout -q "$pin" && make deps && make) ln -sf "$src/spinel/bin/spinel" "$HOME/.local/bin/spinel" ln -sf "$src/tep/bin/tep" "$HOME/.local/bin/tep" } sec_arm64root() { # a Debian arm64 root filesystem, run through proot + qemu (no root needed) root="$TC/arm64root" if ! [ -x "$root/bin/sh" ]; then url=$(curl -fsSL https://images.linuxcontainers.org/meta/1.0/index-system | awk -F';' '$1=="debian" && $2=="trixie" && $3=="arm64" && $4=="default" {print "https://images.linuxcontainers.org"$6"rootfs.tar.xz"}' | tail -1) mkdir -p "$root" curl -fsSL "$url" | tar -xJ -C "$root" --exclude='dev/*' fi rm -f "$root/etc/resolv.conf"; cp /etc/resolv.conf "$root/etc/resolv.conf" "$here/arm64.sh" sh -c 'apt-get update -qq && apt-get install -y -qq build-essential curl git ca-certificates libgmp-dev libsqlite3-dev zlib1g-dev libffi-dev pkg-config xz-utils file ocaml-nox ocaml-findlib opam ghc cabal-install libghc-network-dev >/dev/null' # Mojo for arm64, natively inside the root (pixi's linux-aarch64 build) "$here/arm64.sh" sh -c '[ -x /root/.pixi/bin/mojo ] || { export PIXI_NO_TELEMETRY=1; curl -fsSL https://pixi.sh/install.sh | PIXI_NO_PATH_UPDATE=1 bash >/dev/null; /root/.pixi/bin/pixi global install --environment mojo -c https://conda.modular.com/max -c conda-forge mojo; }' } sections=("$@") [ ${#sections[@]} -gt 0 ] || sections=(base qemu zig rust swift ocaml haskell nim spinel arm64root) for s in "${sections[@]}"; do echo "== $s" "sec_$s" done