#!/usr/bin/env bash # Compila jogos de Ludum Dare de William Lundstedt (Healthire; Rust -> WebAssembly; MIT, Apache-2.0 ou CC0, a escolha de # quem usa) a partir do fonte, num commit fixo, como o scripts/build_web do autor: # cargo build --locked --release --target wasm32-unknown-unknown (Cargo.lock do autor, Rust 1.58.1) # wasm-bindgen --target no-modules --no-typescript (CLI na versao do Cargo.lock: 0.2.67 / 0.2.58) # Imagens, sons e musica entram no .wasm por include_bytes!. A pagina (healthire/index.html.in, healthire/start.js.in) # e nossa: o jogo so inicia depois de um clique, e a politica de seguranca bloqueia conexoes fora da origem. O codigo # do jogo nao e alterado. O CLI do wasm-bindgen so tem binario x86_64 nessas versoes (roda no Rosetta). # # src/FredGames.Bundler/Builds/build-healthire-games.sh [slug ...] (sem argumento: todos) # # O .wasm que o cargo gera (antes do wasm-bindgen) sai igual a cada build, e o script confere o sha256 dele. Ja o # que o wasm-bindgen 0.2.58/0.2.67 escreve (ld4x.js e ld4x_bg.wasm) NAO e byte a byte igual entre execucoes: o CLI # antigo ordena os adaptadores de closures com um HashMap de semente aleatoria, so a ordem muda (o jogo e o mesmo). # O bundle.yaml fixa o sha256 do tar.gz da build testada e conferida no navegador. # # CODEGEN_UNITS=1: com varias unidades o rustc nao gera sempre os mesmos bytes. Rust e wasm-bindgen ficam em # artifacts/tools/. Saida de cada jogo: artifacts/build//{dist/,-dist.tar.gz,-licenses.txt}; o # .tar.gz tem que sair igual em dois builds seguidos. set -euo pipefail here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" root="$(git -C "$here" rev-parse --show-toplevel 2>/dev/null || pwd)" cache="$root/artifacts/build/cache" tools="$root/artifacts/tools" mkdir -p "$cache" export RUSTUP_HOME="$tools/rustup" CARGO_HOME="$tools/cargo" export PATH="$CARGO_HOME/bin:$PATH" TOOLCHAIN=1.58.1 WB_ARCH=x86_64-apple-darwin fetch() { # url arquivo sha256 if [ ! -f "$cache/$2" ]; then curl -fsSL --retry 4 "$1" -o "$cache/$2.partial" && mv "$cache/$2.partial" "$cache/$2" fi echo "$3 $cache/$2" | shasum -a 256 -c - >/dev/null } load() { case "$1" in time-ghosts) REPO=ld47 COMMIT=7c81f24459745e2c930054229d3204005f2ccc87 SHA256=5207688a2f452e388bacb7843ce35a5bd12947687777a9426bf6e57228b94632 CRATE=ld47 TITLE="Time Ghosts" W=800 H=600 REMAP_CARGO=1 CARGO_WASM_SHA=200e7a5cdc0e81aafc2afc3b79516beda04dcf80c46dc8e23da413ef28f396c8 WB=0.2.67 WB_SHA=fc86b356ff6fea4a9794bc92435e1917b84f3acf00056fe83045ddd9a1d8a164 ;; micronaut) REPO=ld48 COMMIT=6ac2159d47903c2b78882e3398e74c2669b1927b SHA256=cc195c48e745b37e8421826c0768da80621e799b6c6dd47edc7ffb1b10382f69 CRATE=ld48 TITLE="Micronaut" W=675 H=675 REMAP_CARGO=0 CARGO_WASM_SHA=84f218f1b23f366db9b3f379597ccfb72470e6c851119769fe5721cd9d771fab WB=0.2.58 WB_SHA=66dfb72be70fbdb128fa67845a5f9d2de8ee1b031fb61a7110c13c7eb30f029d ;; *) echo "jogo desconhecido: $1" >&2; exit 1 ;; esac } build() { local slug="$1" load "$slug" local out="$root/artifacts/build/$slug" tree="$root/artifacts/build/$slug/tree" fetch "https://github.com/Healthire/$REPO/archive/$COMMIT.tar.gz" "$slug-${COMMIT:0:7}.tar.gz" "$SHA256" fetch "https://github.com/rustwasm/wasm-bindgen/releases/download/$WB/wasm-bindgen-$WB-$WB_ARCH.tar.gz" \ "wasm-bindgen-$WB-$WB_ARCH.tar.gz" "$WB_SHA" if [ ! -x "$tools/wasm-bindgen-$WB/wasm-bindgen" ]; then rm -rf "$tools/wasm-bindgen-$WB.tmp"; mkdir -p "$tools/wasm-bindgen-$WB.tmp" tar -xzf "$cache/wasm-bindgen-$WB-$WB_ARCH.tar.gz" -C "$tools/wasm-bindgen-$WB.tmp" --strip-components 1 mv "$tools/wasm-bindgen-$WB.tmp" "$tools/wasm-bindgen-$WB" fi rustup toolchain install "$TOOLCHAIN" --profile minimal --target wasm32-unknown-unknown >/dev/null 2>&1 export RUSTUP_TOOLCHAIN="$TOOLCHAIN" rm -rf "$out"; mkdir -p "$tree" "$out/dist" tar -xzf "$cache/$slug-${COMMIT:0:7}.tar.gz" -C "$tree" --strip-components 1 # Os caminhos do codigo vao para dentro do .wasm (mensagens de panico): o do jogo vira /src e o do CARGO_HOME vira # /cargo. No Micronaut (wasm-bindgen/js-sys 0.2.58/0.3.35) o rustc nao compila o js-sys com o CARGO_HOME remapeado; # ali os caminhos do CARGO_HOME ficam e sao trocados depois, no .wasm, por /cargo com o mesmo tamanho (as barras # repetidas completam o espaco). remap="--remap-path-prefix=$tree=/src" [ "$REMAP_CARGO" = 1 ] && remap="$remap --remap-path-prefix=$CARGO_HOME=/cargo" ( cd "$tree" CARGO_INCREMENTAL=0 CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 RUSTFLAGS="$remap" \ cargo build --locked --release --target wasm32-unknown-unknown 2> "$out/cargo.log" \ || { tail -40 "$out/cargo.log"; exit 1; } if [ "$REMAP_CARGO" != 1 ]; then python3 -I - "target/wasm32-unknown-unknown/release/$CRATE.wasm" "$CARGO_HOME" <<'PY' import sys p, home = sys.argv[1], sys.argv[2].encode() b = open(p, 'rb').read() new = b'/cargo' + b'/' * (len(home) - 6) n = b.count(home) open(p, 'wb').write(b.replace(home, new)) print('caminhos do CARGO_HOME trocados:', n) PY fi echo "$CARGO_WASM_SHA target/wasm32-unknown-unknown/release/$CRATE.wasm" | shasum -a 256 -c - >&2 "$tools/wasm-bindgen-$WB/wasm-bindgen" --target no-modules --no-typescript --out-name "$CRATE" --out-dir "$out/dist" \ "target/wasm32-unknown-unknown/release/$CRATE.wasm" cargo metadata --locked --format-version 1 --filter-platform wasm32-unknown-unknown 2>/dev/null \ | python3 -I "$here/gridbugs/rust-licenses.py" "$CRATE" "$out/crates.txt" ) sed -e "s/@TITLE@/$TITLE/g" -e "s/@NAME@/$CRATE/g" -e "s/@W@/$W/g" -e "s/@H@/$H/g" "$here/healthire/index.html.in" > "$out/dist/index.html" sed -e "s/@NAME@/$CRATE/g" "$here/healthire/start.js.in" > "$out/dist/start.js" { echo "$TITLE - licence" echo "==================" echo echo "Source: https://github.com/Healthire/$REPO at commit $COMMIT. The repository is licensed, at the user's option," echo "under the MIT License, the Apache License 2.0 or CC0 1.0 (files LICENSE-MIT, LICENSE-APACHE, LICENSE-CC0)." echo "The game's pictures, sounds and music are in the repository's assets/ folder and are part of that licence." echo for f in LICENSE-MIT LICENSE-CC0 LICENSE-APACHE; do echo "------------------------------------------------------------------------" echo "$f" echo "------------------------------------------------------------------------" cat "$tree/$f"; echo done echo "========================================================================" cat "$out/crates.txt" } > "$out/$slug-licenses.txt" # dist/ vira um tar.gz deterministico (datas fixas, ordem fixa, sem dono). find "$out/dist" -exec touch -t 202511010000 {} + ( cd "$out" && find dist -type f | LC_ALL=C sort > files.txt \ && COPYFILE_DISABLE=1 tar --format=ustar --uid 0 --gid 0 --uname root --gname root -n -cf - -T files.txt \ | gzip -n -9 > "$slug-${COMMIT:0:7}-dist.tar.gz" && rm files.txt ) rm -rf "$tree" ls -l "$out/$slug-${COMMIT:0:7}-dist.tar.gz" shasum -a 256 "$out/$slug-${COMMIT:0:7}-dist.tar.gz" "$out/$slug-licenses.txt" } for g in "${@:-time-ghosts micronaut}"; do for s in $g; do build "$s"; done; done