carlos / todomvc-bakeoff Public

Clone
git clone https://amadan.net/carlos/todomvc-bakeoff

Plain git — no account needed to clone.

Download

Download this file

1#!/usr/bin/env bash
2# Installs every bakeoff toolchain under $HOME (no sudo), idempotently.
3# scripts/toolchains.sh [section...] sections: base qemu zig rust swift ocaml haskell nim spinel arm64root
4# Then `source scripts/env.sh` puts them on PATH. Versions land in docs/toolchains.md.
5set -euo pipefail
6export PIXI_NO_TELEMETRY=1
7here=$(cd "$(dirname "$0")" && pwd)
8TC=${BAKEOFF_TOOLCHAINS:-$HOME/.local/share/bakeoff-toolchains}
9mkdir -p "$TC" "$HOME/.local/bin"
10dl=$(mktemp -d -p "${TMPDIR:-$HOME/.cache}")
11trap 'rm -rf "$dl"' EXIT
12source "$here/env.sh"
13
14have() { command -v "$1" >/dev/null 2>&1; }
15
16sec_base() { # pixi, plus conda-forge packages for headers and tools Debian lacks here
17 have pixi || curl -fsSL https://pixi.sh/install.sh | PIXI_NO_PATH_UPDATE=1 bash
18 pixi global install --environment bakeoff-base sqlite unzip pkg-config ruby gmp libffi yaml
19}
20
21sec_qemu() { # user-mode arm64 emulator and proot, run explicitly (no binfmt, no root)
22 if ! [ -x "$TC/qemu/qemu-aarch64-static" ]; then
23 # Debian 13's qemu-user ships statically linked binaries (qemu-user-static is transitional)
24 (cd "$dl" && apt-get download qemu-user >/dev/null)
25 dpkg-deb -x "$dl"/qemu-user_*.deb "$dl/q"
26 mkdir -p "$TC/qemu"
27 cp "$dl/q/usr/bin/qemu-aarch64" "$TC/qemu/qemu-aarch64-static"
28 fi
29 ln -sf "$TC/qemu/qemu-aarch64-static" "$HOME/.local/bin/qemu-aarch64-static"
30 if ! [ -x "$TC/proot/proot" ]; then
31 mkdir -p "$TC/proot"
32 curl -fsSL -o "$TC/proot/proot" https://proot.gitlab.io/proot/bin/proot
33 chmod +x "$TC/proot/proot"
34 fi
35 ln -sf "$TC/proot/proot" "$HOME/.local/bin/proot"
36}
37
38sec_zig() {
39 if ! [ -x "$TC/zig/zig" ]; then
40 url=$(curl -fsSL https://ziglang.org/download/index.json |
41 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"])')
42 curl -fsSL "$url" | tar -xJ -C "$dl"
43 rm -rf "$TC/zig" && mv "$dl"/zig-* "$TC/zig"
44 fi
45 ln -sf "$TC/zig/zig" "$HOME/.local/bin/zig"
46}
47
48sec_rust() {
49 have rustup || curl -fsSL https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal
50 rustup toolchain install stable --profile minimal
51 rustup target add aarch64-unknown-linux-musl x86_64-unknown-linux-musl
52 have cargo-zigbuild || cargo install --locked cargo-zigbuild
53}
54
55sec_swift() { # Swift 6.2 is installed; add the Static Linux SDK (musl, x86_64 + aarch64)
56 swift sdk list 2>/dev/null | grep -q static-linux && return
57 v=$(swift --version 2>&1 | sed -n 's/.*Swift version \([0-9.]*\).*/\1/p')
58 idx=$(curl -fsSL "https://www.swift.org/api/v1/install/releases.json")
59 read -r url sum < <(python3 -c '
60import json,sys; v=sys.argv[1]; d=json.loads(sys.argv[2])
61r=[x for x in d if x["name"]==v][0]
62s=[p for p in r["platforms"] if p.get("platform")=="static-sdk" or p.get("name","").lower().startswith("static")][0]
63print("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")
64 swift sdk install "$url" --checksum "$sum"
65}
66
67sec_ocaml() { # opam + OCaml 5 for x86-64; arm64 builds run in the arm64 root (see arm64root)
68 if ! have opam; then
69 curl -fsSL -o "$HOME/.local/bin/opam" "$(curl -fsSL https://api.github.com/repos/ocaml/opam/releases/latest |
70 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])')"
71 chmod +x "$HOME/.local/bin/opam"
72 fi
73 [ -d "$HOME/.opam" ] || opam init --bare -n --disable-sandboxing
74 opam switch list -s | grep -qx bakeoff || opam switch create bakeoff ocaml-base-compiler.5.3.0 -y
75 opam install --switch bakeoff -y dune
76}
77
78sec_haskell() { # ghcup + recommended GHC and cabal for x86-64
79 if ! [ -x "$HOME/.ghcup/bin/ghcup" ]; then
80 curl -fsSL https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh
81 fi
82 ghcup install ghc recommended --set
83 ghcup install cabal recommended --set
84}
85
86sec_mojo() { # Mojo through pixi, as a global environment
87 pixi global install --environment mojo -c https://conda.modular.com/max -c conda-forge mojo
88}
89
90sec_nim() { # Nim (prebuilt x86-64 release); arm64 via zig cc as the C compiler
91 if ! [ -x "$TC/nim/bin/nim" ]; then
92 v=$(curl -fsSL https://nim-lang.org/channels/stable | head -1)
93 curl -fsSL "https://nim-lang.org/download/nim-$v-linux_x64.tar.xz" | tar -xJ -C "$dl"
94 rm -rf "$TC/nim" && mv "$dl/nim-$v" "$TC/nim"
95 fi
96 for b in nim nimble; do ln -sf "$TC/nim/bin/$b" "$HOME/.local/bin/$b"; done
97}
98
99sec_spinel() { # spinel + tep + spinelkit at the pins lpay uses (paulca/lpay spinel/)
100 src="$TC/spinel-src"; mkdir -p "$src"
101 [ -d "$src/lpay" ] || gh repo clone paulca/lpay "$src/lpay" -- --depth 1
102 [ -d "$src/tep" ] || git clone https://github.com/OriPekelman/tep "$src/tep"
103 [ -d "$src/spinelkit" ] || git clone https://github.com/OriPekelman/spinelkit "$src/spinelkit"
104 [ -d "$src/spinel" ] || git clone https://github.com/matz/spinel "$src/spinel"
105 pin=$(head -1 "$src/tep/SPINEL_PIN")
106 (cd "$src/spinel" && git fetch -q origin && git checkout -q "$pin" && make deps && make)
107 ln -sf "$src/spinel/bin/spinel" "$HOME/.local/bin/spinel"
108 ln -sf "$src/tep/bin/tep" "$HOME/.local/bin/tep"
109}
110
111sec_arm64root() { # a Debian arm64 root filesystem, run through proot + qemu (no root needed)
112 root="$TC/arm64root"
113 if ! [ -x "$root/bin/sh" ]; then
114 url=$(curl -fsSL https://images.linuxcontainers.org/meta/1.0/index-system |
115 awk -F';' '$1=="debian" && $2=="trixie" && $3=="arm64" && $4=="default" {print "https://images.linuxcontainers.org"$6"rootfs.tar.xz"}' | tail -1)
116 mkdir -p "$root"
117 curl -fsSL "$url" | tar -xJ -C "$root" --exclude='dev/*'
118 fi
119 rm -f "$root/etc/resolv.conf"; cp /etc/resolv.conf "$root/etc/resolv.conf"
120 "$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'
121 # Mojo for arm64, natively inside the root (pixi's linux-aarch64 build)
122 "$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; }'
123}
124
125sections=("$@")
126[ ${#sections[@]} -gt 0 ] || sections=(base qemu zig rust swift ocaml haskell nim spinel arm64root)
127for s in "${sections[@]}"; do
128 echo "== $s"
129 "sec_$s"
130done
131