mirror of
https://github.com/SpeedBreakerProject/speedbreaker.git
synced 2026-10-18 01:02:13 +02:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
106 lines
5.2 KiB
Bash
Executable File
106 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Rebuild the toolchain from scratch into tools/ (git-ignored).
|
|
#
|
|
# scripts/setup_tools.sh
|
|
#
|
|
# - XenonRecomp at a pinned upstream commit + patches/xenonrecomp/*.patch
|
|
# (branch "nfsmw"), built with Clang.
|
|
# - extract-xiso (to unpack the disc image).
|
|
# - Xenia's PPC instruction tests for the instructions we added.
|
|
#
|
|
# Needs: git, cmake, ninja, clang 18+ (Homebrew LLVM on macOS, the system
|
|
# clang elsewhere; override with LLVM=<bin dir>), lld, make, curl; gh for the
|
|
# instruction tests (skipped without it, or when it isn't logged in).
|
|
set -euo pipefail
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
TOOLS="$ROOT/tools"
|
|
if [ -z "${LLVM:-}" ]; then
|
|
if [ -x /opt/homebrew/opt/llvm/bin/clang ]; then LLVM=/opt/homebrew/opt/llvm/bin
|
|
else LLVM="$(dirname "$(command -v clang)")"; fi
|
|
fi
|
|
sha256() { if command -v sha256sum >/dev/null; then sha256sum -c -; else shasum -a 256 -c -; fi; }
|
|
XENONRECOMP_BASE=ddd128bcca99fe8bfbb99bea583c972351fa6ace # hedge-dev/XenonRecomp main, 2025
|
|
|
|
mkdir -p "$TOOLS"
|
|
|
|
if [ ! -d "$TOOLS/XenonRecomp" ]; then
|
|
git clone --recursive https://github.com/hedge-dev/XenonRecomp.git "$TOOLS/XenonRecomp"
|
|
fi
|
|
cd "$TOOLS/XenonRecomp"
|
|
if ! git rev-parse -q --verify nfsmw >/dev/null; then
|
|
git checkout -q -b nfsmw "$XENONRECOMP_BASE"
|
|
git submodule update --init --recursive
|
|
# The patches carry their own authors; the committer needs any name (a fresh
|
|
# machine or a CI runner has none configured).
|
|
git -c user.name="SpeedBreaker setup" -c user.email=setup@speedbreaker.invalid \
|
|
am -q "$ROOT"/patches/xenonrecomp/*.patch
|
|
fi
|
|
# The bundled fmt predates libc++ dropping transitive <cstdlib>.
|
|
cmake -Wno-deprecated -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
|
-DCMAKE_C_COMPILER="$LLVM/clang" -DCMAKE_CXX_COMPILER="$LLVM/clang++" \
|
|
"-DCMAKE_CXX_FLAGS=-include cstdlib" > /dev/null
|
|
ninja -C build XenonRecomp XenonAnalyse
|
|
|
|
if [ ! -x "$TOOLS/extract-xiso/build/extract-xiso" ]; then
|
|
[ -d "$TOOLS/extract-xiso" ] || git clone -q --depth 1 https://github.com/XboxDev/extract-xiso.git "$TOOLS/extract-xiso"
|
|
cmake -Wno-deprecated -S "$TOOLS/extract-xiso" -B "$TOOLS/extract-xiso/build" -G Ninja -DCMAKE_BUILD_TYPE=Release > /dev/null
|
|
ninja -C "$TOOLS/extract-xiso/build"
|
|
fi
|
|
|
|
# FFmpeg for XMA audio: a minimal static libavcodec (XMA1/XMA2/WMAPro
|
|
# decoders only) with patches/ffmpeg applied (scripts/build_ffmpeg_xma.sh).
|
|
# On macOS it is linked into the game, so it is built for the oldest macOS
|
|
# the game runs on (CMakeLists.txt's SB_OSX_DEFAULT_TARGET), not this Mac's
|
|
# own; one built for another macOS is rebuilt.
|
|
FFMPEG_VERSION=7.1.1
|
|
FFMPEG_SHA256=733984395e0dbbe5c046abda2dc49a5544e7e0e1e2366bba849222ae9e3a03b1
|
|
ffmpeg_ok=1
|
|
[ -f "$TOOLS/ffmpeg-xma/lib/libavcodec.a" ] || ffmpeg_ok=0
|
|
if [ "$(uname -s)" = Darwin ]; then
|
|
export MACOSX_DEPLOYMENT_TARGET="$(sed -n 's/^set(SB_OSX_DEFAULT_TARGET "\([0-9.]*\)").*/\1/p' "$ROOT/CMakeLists.txt" | head -1)"
|
|
[ -n "$MACOSX_DEPLOYMENT_TARGET" ] || { echo "no SB_OSX_DEFAULT_TARGET in $ROOT/CMakeLists.txt"; exit 1; }
|
|
if [ $ffmpeg_ok = 1 ] && [ "$(otool -l "$TOOLS/ffmpeg-xma/lib/libavcodec.a" "$TOOLS/ffmpeg-xma/lib/libavutil.a" \
|
|
| awk '/LC_BUILD_VERSION/{b=1} b&&/minos/{print $2; b=0}' | sort -u)" != "$MACOSX_DEPLOYMENT_TARGET" ]; then
|
|
echo "tools/ffmpeg-xma isn't built for macOS $MACOSX_DEPLOYMENT_TARGET: rebuilding it"; ffmpeg_ok=0
|
|
fi
|
|
fi
|
|
if [ $ffmpeg_ok = 0 ]; then
|
|
mkdir -p "$TOOLS/ffmpeg-src"
|
|
cd "$TOOLS/ffmpeg-src"
|
|
[ -f "ffmpeg-$FFMPEG_VERSION.tar.xz" ] || curl -sfLO "https://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.xz"
|
|
echo "$FFMPEG_SHA256 ffmpeg-$FFMPEG_VERSION.tar.xz" | sha256
|
|
"$ROOT/scripts/build_ffmpeg_xma.sh" "$TOOLS/ffmpeg-src/ffmpeg-$FFMPEG_VERSION.tar.xz" "$TOOLS/ffmpeg-xma"
|
|
# The license texts, for the SteamOS bundle's licenses/ (make_bundle.sh).
|
|
tar -xf "ffmpeg-$FFMPEG_VERSION.tar.xz" "ffmpeg-$FFMPEG_VERSION/COPYING.LGPLv2.1" "ffmpeg-$FFMPEG_VERSION/LICENSE.md"
|
|
cd "$ROOT"
|
|
fi
|
|
|
|
mkdir -p "$TOOLS/xenia-tests"
|
|
missing=()
|
|
for t in vslw vand vsel mulhw vslh vsrah vsubshs vspltish vmaxsh vandc vctuxs vpkswss \
|
|
vminsh vavguh vpkswus vsrh vrlh vpkshss vpkuhus mulhd mulhdu; do
|
|
[ -s "$TOOLS/xenia-tests/instr_$t.s" ] || missing+=("$t")
|
|
done
|
|
# They come through gh. Without it, or logged out, everything else is ready:
|
|
# only tests/run_instr_tests.sh lacks its inputs, so that isn't a failure.
|
|
if [ ${#missing[@]} -gt 0 ]; then
|
|
if ! command -v gh >/dev/null; then
|
|
echo "gh not found: skipping Xenia's instruction tests (only tests/run_instr_tests.sh needs them)"; missing=()
|
|
elif ! gh auth status >/dev/null 2>&1; then
|
|
echo "gh isn't logged in (gh auth login): skipping Xenia's instruction tests (only tests/run_instr_tests.sh needs them)"; missing=()
|
|
fi
|
|
fi
|
|
for t in ${missing[@]+"${missing[@]}"}; do
|
|
f="$TOOLS/xenia-tests/instr_$t.s"
|
|
# Into a temporary file first: a failed fetch must not leave an empty test
|
|
# that later runs would skip as already fetched.
|
|
if gh api "repos/xenia-project/xenia/contents/src/xenia/cpu/ppc/testing/instr_$t.s" \
|
|
-H "Accept: application/vnd.github.raw" > "$f.part" && [ -s "$f.part" ]; then
|
|
mv "$f.part" "$f"
|
|
else
|
|
rm -f "$f.part"; echo "couldn't fetch Xenia's instr_$t.s"; exit 1
|
|
fi
|
|
done
|
|
|
|
echo "tools ready: $(git -C "$TOOLS/XenonRecomp" log --oneline -1)"
|