mirror of
https://github.com/Toastconcern/FrameStudio.git
synced 2026-10-28 21:02:20 +01:00
ci: Build Frame Home in CI
Build Frame Home payload in CI Build the ARM64 headset payload against the glibc 2.39 baseline, validate its ABI, and pass the generated artifact to Studio packaging. Add provenance attestations and document CI and local build modes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
7 files changed
+257
-103
No files matched your search
@@ -0,0 +1,122 @@
|
||||
#!/bin/sh
|
||||
# Build the Steam Frame payload and its standalone installer on an ARM64 glibc 2.39 runner.
|
||||
set -eu
|
||||
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
||||
OUT=${FRAME_HOME_OUTPUT_DIR:-"$ROOT/build/frame-home"}
|
||||
PAYLOAD="$OUT/payload"
|
||||
MODE=${1:-${FRAME_HOME_BUILD_MODE:-local}}
|
||||
case "$MODE" in
|
||||
ci|--ci)
|
||||
MODE=ci
|
||||
BUILD=${FRAME_HOME_BUILD_DIR:-"$ROOT/build/frame-home-cmake-ci"}
|
||||
CC=${CC:-gcc-13}
|
||||
CXX=${CXX:-g++-13}
|
||||
;;
|
||||
local|--local)
|
||||
MODE=local
|
||||
BUILD=${FRAME_HOME_BUILD_DIR:-"$ROOT/build/frame-home-cmake-local"}
|
||||
CC=${CC:-gcc}
|
||||
CXX=${CXX:-g++}
|
||||
;;
|
||||
*) echo "Usage: $0 [--local|--ci]" >&2; exit 2 ;;
|
||||
esac
|
||||
export CC CXX
|
||||
|
||||
[ "$(uname -m)" = aarch64 ] || { echo "Frame Home requires an ARM64 runner" >&2; exit 1; }
|
||||
if [ "$MODE" = ci ] && [ "$(getconf GNU_LIBC_VERSION)" != "glibc 2.39" ]; then
|
||||
echo "Release builds require glibc 2.39 (found: $(getconf GNU_LIBC_VERSION))" >&2
|
||||
exit 1
|
||||
fi
|
||||
for tool in cmake ninja "$CC" "$CXX" glslc readelf zip python3; do
|
||||
command -v "$tool" >/dev/null 2>&1 || { echo "Missing build tool: $tool" >&2; exit 1; }
|
||||
done
|
||||
if [ "$MODE" = ci ]; then
|
||||
"$CXX" --version | grep -q '13\.' || { echo "Release builds require GCC 13" >&2; exit 1; }
|
||||
fi
|
||||
|
||||
if [ "$MODE" = local ]; then
|
||||
cmake -S "$ROOT" -B "$BUILD" -G Ninja -DCMAKE_BUILD_TYPE=Release -DFRAME_HOME_PC=OFF \
|
||||
"-DOPENVR_LIB_DIR=${OPENVR_LIB_DIR:-/opt/steamvr/bin/linuxarm64}"
|
||||
else
|
||||
cmake -S "$ROOT" -B "$BUILD" -G Ninja -DCMAKE_BUILD_TYPE=Release -DFRAME_HOME_PC=ON
|
||||
fi
|
||||
cmake --build "$BUILD" --target frame-home frame-switcher fenv-tool --parallel
|
||||
|
||||
rm -rf "$PAYLOAD" "$OUT/FrameHome-installer-stage" "$OUT/FrameHome-installer.zip"
|
||||
mkdir -p "$PAYLOAD/bin" "$PAYLOAD/layer"
|
||||
cp "$BUILD/frame-home" "$BUILD/frame-switcher" "$BUILD/fenv-tool" "$PAYLOAD/bin/"
|
||||
"$CXX" -O2 -shared -fPIC -std=c++17 -fvisibility=hidden \
|
||||
-I"$ROOT/third_party/vulkan-headers/include" -I"$ROOT/src" \
|
||||
"$ROOT/layer/frame_home_layer.cpp" -o "$PAYLOAD/layer/libframe_home_layer.so" -lpthread
|
||||
glslc "$ROOT/layer/env_ps.frag" -o "$PAYLOAD/layer/env_ps.spv"
|
||||
cp "$ROOT/frame/payload/install.sh" "$PAYLOAD/install.sh"
|
||||
chmod +x "$PAYLOAD/install.sh" "$PAYLOAD/bin/"*
|
||||
|
||||
for binary in "$PAYLOAD/bin/"* "$PAYLOAD/layer/libframe_home_layer.so"; do
|
||||
readelf -h "$binary" | grep -q 'Machine:.*AArch64' || {
|
||||
echo "Not an AArch64 ELF: $binary" >&2; exit 1;
|
||||
}
|
||||
highest=$(readelf --version-info "$binary" | grep -oE 'GLIBC_[0-9]+(\.[0-9]+)+' | sort -Vu | tail -n 1 || true)
|
||||
if [ "$MODE" = ci ] && [ -n "$highest" ] && [ "$(printf '%s\n' "$highest" GLIBC_2.39 | sort -V | tail -n 1)" != GLIBC_2.39 ]; then
|
||||
echo "$binary requires $highest, newer than the glibc 2.39 baseline" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
STAGE="$OUT/FrameHome-installer-stage/FrameHome-installer"
|
||||
mkdir -p "$STAGE"
|
||||
cp -R "$PAYLOAD" "$STAGE/payload"
|
||||
cp "$ROOT/LICENSE" "$STAGE/LICENSE.txt"
|
||||
cp "$ROOT/frame/install-frame-home.sh" "$ROOT/frame/install-frame-home.ps1" \
|
||||
"$ROOT/frame/Install Frame Home.bat" "$ROOT/frame/README-frame-home.txt" "$STAGE/"
|
||||
chmod +x "$STAGE/install-frame-home.sh"
|
||||
(cd "$OUT/FrameHome-installer-stage" && zip -qr "$OUT/FrameHome-installer.zip" FrameHome-installer)
|
||||
rm -rf "$OUT/FrameHome-installer-stage"
|
||||
python3 - "$OUT/FrameHome-installer.zip" <<'PY'
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
required = {
|
||||
"FrameHome-installer/payload/install.sh",
|
||||
"FrameHome-installer/payload/bin/frame-home",
|
||||
"FrameHome-installer/payload/bin/frame-switcher",
|
||||
"FrameHome-installer/payload/bin/fenv-tool",
|
||||
"FrameHome-installer/payload/layer/libframe_home_layer.so",
|
||||
"FrameHome-installer/payload/layer/env_ps.spv",
|
||||
}
|
||||
allowed_files = {
|
||||
"FrameHome-installer/LICENSE.txt",
|
||||
"FrameHome-installer/Install Frame Home.bat",
|
||||
"FrameHome-installer/install-frame-home.ps1",
|
||||
"FrameHome-installer/install-frame-home.sh",
|
||||
"FrameHome-installer/README-frame-home.txt",
|
||||
}
|
||||
with zipfile.ZipFile(sys.argv[1]) as archive:
|
||||
names = {name.rstrip("/") for name in archive.namelist()}
|
||||
missing = required - names
|
||||
unexpected = {
|
||||
name for name in names
|
||||
if name != "FrameHome-installer"
|
||||
and name not in allowed_files
|
||||
and not name.startswith("FrameHome-installer/payload/")
|
||||
}
|
||||
if missing or unexpected:
|
||||
raise SystemExit(f"Invalid Frame Home installer: missing={sorted(missing)}, unexpected={sorted(unexpected)}")
|
||||
PY
|
||||
{
|
||||
printf 'mode=%s\n' "$MODE"
|
||||
printf 'architecture=%s\n' "$(uname -m)"
|
||||
printf 'libc=%s\n' "$(getconf GNU_LIBC_VERSION)"
|
||||
printf 'c_compiler=%s\n' "$("$CC" --version | head -n 1)"
|
||||
printf 'cxx_compiler=%s\n' "$("$CXX" --version | head -n 1)"
|
||||
printf 'cmake=%s\n' "$(cmake --version | head -n 1)"
|
||||
printf 'ninja=%s\n' "$(ninja --version)"
|
||||
printf 'glslc=%s\n' "$(glslc --version | head -n 1)"
|
||||
} > "$OUT/build-info.txt"
|
||||
for binary in "$PAYLOAD/bin/"* "$PAYLOAD/layer/libframe_home_layer.so"; do
|
||||
printf '\n[%s]\n' "${binary#"$PAYLOAD/"}" >> "$OUT/build-info.txt"
|
||||
readelf -d "$binary" | grep -E 'NEEDED|RPATH|RUNPATH' >> "$OUT/build-info.txt" || true
|
||||
readelf --version-info "$binary" | grep -oE '(GLIBC|GLIBCXX|CXXABI)_[0-9]+(\.[0-9]+)+' | sort -Vu | tr '\n' ' ' >> "$OUT/build-info.txt" || true
|
||||
printf '\n' >> "$OUT/build-info.txt"
|
||||
done
|
||||
echo "Built $OUT/payload, $OUT/FrameHome-installer.zip, and $OUT/build-info.txt"
|
||||
+9
-22
@@ -10,14 +10,13 @@
|
||||
# (on Windows itself: studio\build_windows.bat x64|x86|arm64)
|
||||
# macos-arm64 macos-x64 on a Mac with Xcode's command line tools; MoltenVK is bundled into the
|
||||
# app from $MOLTENVK (a libMoltenVK.dylib) or Homebrew's molten-vk
|
||||
# frame-home the Steam Frame installer on its own (no Studio needed): the headset
|
||||
# files from frame/payload and the install scripts
|
||||
# all every target this computer can build
|
||||
# Output: dist/FrameStudio-<target>.zip (.tar.gz on Linux) and dist/FrameHome-installer.zip.
|
||||
# Output: dist/FrameStudio-<target>.zip (.tar.gz on Linux).
|
||||
set -eu
|
||||
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
||||
DIST="$ROOT/dist"
|
||||
BUILD="$ROOT/build"
|
||||
FRAME_PAYLOAD_DIR=${FRAME_HOME_PAYLOAD_DIR:-"$ROOT/frame/payload"}
|
||||
CMAKE=${CMAKE:-cmake}
|
||||
TARGETS=""
|
||||
while [ $# -gt 0 ]; do
|
||||
@@ -33,10 +32,10 @@ say() { echo "build-studio: $*"; }
|
||||
|
||||
if [ "$TARGETS" = " all" ]; then
|
||||
case "$(uname -s)" in
|
||||
Darwin) TARGETS="macos-arm64 macos-x64 frame-home" ;;
|
||||
Darwin) TARGETS="macos-arm64 macos-x64" ;;
|
||||
*) case "$(uname -m)" in
|
||||
aarch64|arm64) TARGETS="linux-arm64 frame-home" ;;
|
||||
*) TARGETS="linux-x64 linux-x86 frame-home" ;;
|
||||
aarch64|arm64) TARGETS="linux-arm64" ;;
|
||||
*) TARGETS="linux-x64 linux-x86" ;;
|
||||
esac
|
||||
[ -x "${LLVM_MINGW:-$HOME/.local/opt/llvm-mingw}/bin/x86_64-w64-mingw32-clang" ] && TARGETS="$TARGETS windows-x64 windows-x86 windows-arm64" ;;
|
||||
esac
|
||||
@@ -47,7 +46,8 @@ build() {
|
||||
target=$1; shift
|
||||
dir="$BUILD/$target"
|
||||
say "building $target"
|
||||
"$CMAKE" -S "$ROOT/studio" -B "$dir" -DCMAKE_BUILD_TYPE=Release "$@" > "$dir.configure.log" 2>&1 || {
|
||||
"$CMAKE" -S "$ROOT/studio" -B "$dir" -DCMAKE_BUILD_TYPE=Release \
|
||||
"-DFRAME_HOME_PAYLOAD_DIR=$FRAME_PAYLOAD_DIR" "$@" > "$dir.configure.log" 2>&1 || {
|
||||
tail -20 "$dir.configure.log"; say "$target: configure failed (full log: $dir.configure.log)"; exit 1; }
|
||||
"$CMAKE" --build "$dir" --target frame-studio --parallel
|
||||
}
|
||||
@@ -73,8 +73,8 @@ stage_pc() {
|
||||
cp "$home/frame-home" "$home/frame-switcher" "$stage/pc/bin/"
|
||||
${CXX:-g++} -O2 -shared -fPIC -std=c++17 -fvisibility=hidden -I"$ROOT/third_party/vulkan-headers/include" -I"$ROOT/src" \
|
||||
"$ROOT/layer/frame_home_layer.cpp" -o "$stage/pc/layer/libframe_home_layer.so" -lpthread
|
||||
cp "$ROOT/frame/payload/layer/env_ps.spv" "$stage/pc/layer/"
|
||||
cp "$ROOT/frame/payload/install.sh" "$stage/pc/" && chmod +x "$stage/pc/install.sh" "$stage"/pc/bin/* ;;
|
||||
cp "$FRAME_PAYLOAD_DIR/layer/env_ps.spv" "$stage/pc/layer/"
|
||||
cp "$FRAME_PAYLOAD_DIR/install.sh" "$stage/pc/" && chmod +x "$stage/pc/install.sh" "$stage"/pc/bin/* ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -112,18 +112,6 @@ bundle_moltenvk() {
|
||||
fi
|
||||
}
|
||||
|
||||
# dist/FrameHome-installer.zip: Frame Home for the Steam Frame, installed without Frame Studio
|
||||
package_frame_home() {
|
||||
stage="$BUILD/stage/FrameHome-installer"
|
||||
rm -rf "$stage" && mkdir -p "$stage"
|
||||
cp -R "$ROOT/frame/payload" "$stage/payload"
|
||||
cp "$ROOT/LICENSE" "$stage/LICENSE.txt"
|
||||
cp "$ROOT/frame/install-frame-home.sh" "$ROOT/frame/install-frame-home.ps1" "$ROOT/frame/Install Frame Home.bat" "$ROOT/frame/README-frame-home.txt" "$stage/"
|
||||
chmod +x "$stage/install-frame-home.sh" "$stage/payload/install.sh" "$stage"/payload/bin/* 2>/dev/null || true
|
||||
(cd "$BUILD/stage" && rm -f "$DIST/FrameHome-installer.zip" && zip -qr "$DIST/FrameHome-installer.zip" FrameHome-installer)
|
||||
say "frame-home -> dist/FrameHome-installer.zip"
|
||||
}
|
||||
|
||||
for t in $TARGETS; do
|
||||
case "$t" in
|
||||
linux-x64) build "$t" -G Ninja && build_pc_home "$t" -G Ninja && package "$t" ;;
|
||||
@@ -135,7 +123,6 @@ for t in $TARGETS; do
|
||||
windows-arm64) build "$t" -G Ninja -DCMAKE_TOOLCHAIN_FILE="$ROOT/cmake/llvm-mingw.cmake" -DWINDOWS_ARCH=aarch64 && package "$t" ;;
|
||||
macos-arm64) build "$t" -G Ninja -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 && package "$t" ;;
|
||||
macos-x64) build "$t" -G Ninja -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 && package "$t" ;;
|
||||
frame-home) package_frame_home ;;
|
||||
*) say "unknown target: $t (see --help)"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
Reference in new issue
Block a user