Files
ppsspp/.github/workflows/build.yml
T
Henrik RydgårdandClaude Opus 5 9a29bf84d8 Add a riscv64 cross build, generalizing the loongarch64 one
The pieces were nearly all in place already - CMakeLists has detected
riscv64 and set RISCV64 since the backend landed - so this is mostly a
matter of not hardcoding loongarch64 in the cross-build plumbing:

- setup-loongarch64-cross.sh becomes setup-cross.sh <target>, taking the
  triple and dynamic linker name from the argument.
- b.sh gains --riscv64, and the GL stub block is keyed off a compiler
  variable rather than a loongarch64-only flag.
- New cmake/Toolchains/riscv64-linux-gnu.cmake, mirroring the existing one.

The SDL carve-out moves from LOONGARCH64_DEVICE to a new HEADLESS_CROSS
option set by b.sh. That flag was keyed off the target architecture, which
is also true when building natively on such a machine - harmless so far,
but riscv64 hardware that people actually build PPSSPP on exists, and it
should still get the normal SDL frontend.

Both toolchain files now find qemu rather than assuming the static build:
Debian ships the static binaries in qemu-user-static and the dynamic ones
in qemu-user, and only the latter is available on some releases. Neither
being present is fine too - it just means no compile-check programs run.

Verified by a clean loongarch64 build; riscv64 is untested so far, the
toolchain isn't installed here yet.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-19 11:52:16 -06:00

562 lines
19 KiB
YAML

name: Build
on:
push:
branches:
- master
# For testing.
- actions
tags:
- "v*.*"
paths-ignore:
- '*.{txt,md}'
- 'Tools/**'
- '.{editorconfig,gitattributes,gitignore}'
- 'appveyor.yml'
pull_request:
branches:
- master
paths-ignore:
- '*.{txt,md}'
- 'Tools/**'
- '.{editorconfig,gitattributes,gitignore}'
- 'appveyor.yml'
env:
BUILD_CONFIGURATION: Release
jobs:
build-windows:
strategy:
fail-fast: false
matrix:
platform: [x64, ARM64]
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
with:
submodules: recursive
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0
- name: Check Valid Version Tags
id: valid-tags
shell: bash
run: |
# This is required for git describe --always to work for git-version.cpp.
git fetch --deepen=15000 --no-recurse-submodules --tags || exit 0
echo "count=$(git tag -l 'v[0-9]*' | wc -l | tr -d ' ')" >> $GITHUB_OUTPUT # $env:GITHUB_OUTPUT on pwsh
- name: Fetch upstream tags # Fallback to fetching tags from upstream
if: steps.valid-tags.outputs.count == '0'
shell: bash
run: |
# TODO: should try to fetch tags from whereever this repo was forked from before fetching from official repo
git remote add upstream https://github.com/hrydgard/ppsspp.git
git fetch --deepen=15000 --no-recurse-submodules --tags --force upstream || exit 0
- name: Create git-version.cpp for Windows # Not sure why the one at git-version-gen.cmd couldn't get the version properly.
#if: github.ref_type == 'tag'
run: |
$GIT_VERSION=git describe --always
echo "Num of Valid Tags = ${{ steps.valid-tags.outputs.count }}"
echo "Test GitVer = ${{ github.ref_name }} / $GIT_VERSION / ${GITHUB_REF_NAME}"
echo "const char *PPSSPP_GIT_VERSION = `"$GIT_VERSION`";" > git-version.cpp
echo "#define PPSSPP_GIT_VERSION_NO_UPDATE 1" >> git-version.cpp
# Generate Windows/win-version.h too.
if ($GIT_VERSION.StartsWith("v")) {
$WIN_VERSION_COMMA=$GIT_VERSION -replace '^v', '' -replace '-g[0-9a-f]+$', '' -replace '[-\.]', ','
echo "Test WinVer = $WIN_VERSION_COMMA"
echo "#define PPSSPP_WIN_VERSION_STRING `"$GIT_VERSION`"" > Windows/win-version.h
echo "#define PPSSPP_WIN_VERSION_COMMA $WIN_VERSION_COMMA" >> Windows/win-version.h
echo "#define PPSSPP_WIN_VERSION_NO_UPDATE 1" >> Windows/win-version.h
}
- name: Build Windows
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: msbuild /m /p:TrackFileAccess=false /p:Configuration=${{ env.BUILD_CONFIGURATION }} /p:Platform=${{ matrix.platform }} Windows/PPSSPP.sln
- name: Package build
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
mkdir ppsspp
cp PPSSPP*.exe ppsspp/
cp *.pdb ppsspp/
cp Windows/*.bat ppsspp/
cp -r assets ppsspp/assets
- name: Package headless (non-Win32)
if: matrix.platform != 'Win32'
run: cp Windows/${{ matrix.platform }}/Release/*.exe ppsspp/
- name: Package headless (Win32)
if: matrix.platform == 'Win32'
run: cp Windows/Release/*.exe ppsspp/
- name: Upload build
uses: actions/upload-artifact@v7
with:
name: Windows ${{ matrix.platform }} build
path: ppsspp/
- name: Create release
if: github.ref_type == 'tag'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
rm ppsspp/PPSSPPHeadless*
rm ppsspp/UnitTest*
rm ppsspp/*.pdb
mkdir releases
Compress-Archive -Path "ppsspp/*" -Update -DestinationPath "releases/PPSSPP-${{ github.ref_name }}-Windows-${{ matrix.platform }}.zip"
- name: Upload release
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
if: github.ref_type == 'tag'
with:
files: releases/*.zip
build-uwp:
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
with:
submodules: recursive
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0
- name: Restore NuGet packages
working-directory: ${{ github.workspace }}/UWP
run: nuget restore PPSSPP_UWP.sln
- name: Build UWP
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: msbuild /m /p:TrackFileAccess=false /p:Configuration=${{ env.BUILD_CONFIGURATION }} /p:Platform=x64 /p:AppxPackageSigningEnabled=false UWP/PPSSPP_UWP.sln
# Mirrors the two Windows jobs in libretro's own GitLab CI (see .gitlab-ci.yml). The libretro core
# is built by GNU make driving cl.exe/link.exe from an MSYS2 shell, not by the VS solution, so it
# catches MSVC-specific errors that neither build-windows nor the Linux/Android libretro builds do
# - duplicate symbols in particular, since MSVC emits inline functions that gcc/clang inline away.
build-libretro-windows:
name: build-libretro-windows (${{ matrix.arch }})
strategy:
fail-fast: false
matrix:
include:
- arch: x64
platform: windows_msvc2019_desktop_x64
msystem: MINGW64
- arch: x86
platform: windows_msvc2019_desktop_x86
msystem: MINGW32
runs-on: windows-latest
timeout-minutes: 90
steps:
- uses: actions/checkout@v7
with:
submodules: recursive
# Needs a real MSYS2 (make, bash, cygpath) - the one preinstalled on the runner image isn't on
# PATH and has no make. path-type: inherit keeps the Windows PATH, which the Makefile needs for
# reg.exe (Windows SDK lookup) and git.
- name: Setup MSYS2
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0
with:
msystem: ${{ matrix.msystem }}
path-type: inherit
install: make
# The Makefile can locate Visual Studio by itself, but only through "cmd //c bash VSWhere.sh",
# which depends on COMSPEC and ProgramFiles(x86) surviving into the MSYS2 shell. Resolving it
# here and passing VsInstallRoot= on the command line (a command-line variable overrides the
# Makefile's own := assignment) fails loudly rather than silently misconfiguring the build.
- name: Build libretro core
shell: msys2 {0}
run: |
VS_PATH=$(sh libretro/VSWhere.sh -latest -property installationPath)
test -n "$VS_PATH" || { echo "vswhere found no Visual Studio installation"; exit 1; }
echo "Visual Studio: $VS_PATH"
make -C libretro -f Makefile -j4 platform=${{ matrix.platform }} VsInstallRoot="$(cygpath -u "$VS_PATH")"
test-windows:
runs-on: windows-latest
needs: build-windows
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
with:
submodules: false
- name: Fetch tests
working-directory: ${{ env.GITHUB_WORKSPACE }}
# Doing this to avoid ffmpeg and other large submodules.
run: git submodule update --init pspautotests assets/lang
- name: Download build
uses: actions/download-artifact@v8
with:
name: Windows x64 build
path: ppsspp/
- name: Execute unit tests
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: ppsspp\\UnitTest.exe ALL
- name: Execute headless tests
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: python test.py -g --graphics=software
build:
name: build (${{ matrix.id }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-26.04
extra: test
cc: clang
cxx: clang++
args: ./b.sh --headless --unittest
id: clang-normal
- os: ubuntu-26.04
cc: gcc
cxx: g++
args: ./b.sh --headless --unittest
id: gcc-normal
- os: ubuntu-26.04
extra: android
cc: clang
cxx: clang++
args: cd android && ./ab.sh APP_ABI=arm64-v8a UNITTEST=1 HEADLESS=1
id: android-arm64
- os: ubuntu-26.04
extra: android
cc: clang
cxx: clang++
args: cd android && ./ab.sh APP_ABI=armeabi-v7a UNITTEST=1 HEADLESS=1
id: android-arm32
- os: ubuntu-26.04
extra: android
cc: clang
cxx: clang++
args: cd android && ./ab.sh APP_ABI=x86_64 UNITTEST=1 HEADLESS=1
id: android-x86_64
- os: ubuntu-26.04
extra: android
cc: clang
cxx: clang++
args: cd android && ./ab.sh APP_ABI=arm64-v8a OPENXR=1
id: android-vr
- os: ubuntu-26.04
extra: android
cc: clang
cxx: clang++
args: ./b.sh --libretro_android ppsspp_libretro
id: android-libretro
- os: ubuntu-26.04
extra: libretro
cc: gcc
cxx: g++
args: make -C libretro -f Makefile -j2
id: gcc-libretro
- os: ubuntu-26.04
extra: libretro
cc: clang
cxx: clang++
args: make -C libretro -f Makefile -j2
id: clang-libretro
- os: ubuntu-26.04
extra: loongarch64
cc: gcc
cxx: g++
args: ./b.sh --loongarch64 PPSSPPHeadless
id: loongarch64
- os: ubuntu-26.04
extra: riscv64
cc: gcc
cxx: g++
args: ./b.sh --riscv64 PPSSPPHeadless
id: riscv64
- os: macos-latest
extra: test
cc: clang
cxx: clang++
args: ./b.sh --headless --unittest --no-png
id: macos
- os: macos-latest
extra: libretro_mac
cc: clang
cxx: clang++
args: ./b.sh --libretro
id: macos-libretro
- os: macos-latest
extra: ios
cc: clang
cxx: clang++
args: ./b-ios.sh
id: ios
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
with:
submodules: recursive
- name: Fetch tags for macOS releases
if: runner.os == 'macOS'
# This is required for git describe --always to work for git-version.cpp.
run: |
git fetch --deepen=15000 --no-recurse-submodules --tags || exit 0
- name: Setup Android NDK
uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0
if: matrix.extra == 'android'
id: setup-ndk
with:
ndk-version: r29
- name: Install Linux dependencies
if: runner.os == 'Linux' && matrix.extra != 'android' && matrix.extra != 'loongarch64' && matrix.extra != 'riscv64'
run: |
sudo apt-get update -y -qq
sudo apt-get install libsdl3-dev libgl1-mesa-dev libglu1-mesa-dev libsdl3-ttf-dev libfontconfig1-dev libcurl4-openssl-dev
- name: Install macOS SDL3 dependencies
if: runner.os == 'macOS' && matrix.id == 'macos'
run: brew install sdl3 sdl3_ttf
- name: Install cross-compilation dependencies
if: matrix.extra == 'loongarch64' || matrix.extra == 'riscv64'
run: |
sudo apt-get update -y -qq
sudo apt-get install -y gcc-14-${{ matrix.extra }}-linux-gnu g++-14-${{ matrix.extra }}-linux-gnu binutils-${{ matrix.extra }}-linux-gnu libgl-dev libglu1-mesa-dev
sudo cmake/scripts/setup-cross.sh ${{ matrix.extra }}
- name: Install iOS dependencies
if: matrix.id == 'ios'
run: |
brew install ldid dpkg pillow
# Check Xcode version
xcodebuild -version
- name: Create iOS Version.txt file
if: matrix.id == 'ios'
run: |
# Create Version.txt file (should probably do this during building process)
mkdir -p build-ios/PPSSPP.app
GIT_VERSION=$(git describe --always --tags)
echo ${GIT_VERSION#v} > build-ios/PPSSPP.app/Version.txt
- name: Create macOS & iOS git-version.cpp for tagged release
if: github.ref_type == 'tag' && (matrix.id == 'macos' || matrix.id == 'ios')
run: |
echo "const char *PPSSPP_GIT_VERSION = \"${GITHUB_REF_NAME}\";" > git-version.cpp
echo "#define PPSSPP_GIT_VERSION_NO_UPDATE 1" >> git-version.cpp
- name: Setup ccache
uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23
# Disable ccache on macos for now, it's become buggy for some reason.
if: matrix.id != 'macos'
with:
key: ${{ matrix.id }}
- name: Execute build
env:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
NDK: ${{ steps.setup-ndk.outputs.ndk-path }}
NDK_CCACHE: ccache
USE_CCACHE: 1
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
export CCACHE_SLOPPINESS=clang_index_store,ivfsoverlay,include_file_ctime,include_file_mtime,modules,system_headers,time_macros
if [ "${{ matrix.extra }}" == "android" ]; then
export CCACHE_FILECLONE=true
export CCACHE_DEPEND=true
export CCACHE_COMPILERCHECK=content
elif [ "$RUNNER_OS" == "macOS" ]; then
export CCACHE_SLOPPINESS=pch_defines,$CCACHE_SLOPPINESS
export CCACHE_FILECLONE=true
export CCACHE_DEPEND=true
export CCACHE_COMPILERCHECK=content
fi
${{ matrix.args }}
- name: Package build
if: matrix.extra == 'test' || matrix.id == 'ios'
run: |
mkdir -p ppsspp
if [ -e build*/$BUILD_CONFIGURATION/PPSSPPSDL ]; then
cp build*/$BUILD_CONFIGURATION/PPSSPPSDL ppsspp/
elif [ -e build*/PPSSPPSDL.app ]; then
cp -a build*/PPSSPPSDL.app ppsspp/
# GitHub Actions zipping kills symlinks and permissions.
pushd ppsspp
zip -qry PPSSPPSDL.zip PPSSPPSDL.app
rm -rf PPSSPPSDL.app
popd
elif [ -e build-ios/PPSSPP.app ]; then
# Get the final files generated by b-ios.h script
find build -name 'PPSSPP*.ipa' -exec cp -a '{}' ppsspp/ \;
find build -name 'PPSSPP*.xcarchive' -exec cp -a '{}' ppsspp/ \;
find build -name 'PPSSPP*.deb' -exec cp -a '{}' ppsspp/ \;
find build -name 'org.ppsspp*.deb' -exec cp -a '{}' ppsspp/ \;
elif [ -e build*/PPSSPPSDL ]; then
cp build*/PPSSPPSDL ppsspp/
cp -r assets ppsspp/assets
fi
if [ -e build*/$BUILD_CONFIGURATION/PPSSPPHeadless ]; then
cp build*/$BUILD_CONFIGURATION/PPSSPPHeadless ppsspp/
elif [ -e build*/PPSSPPHeadless ]; then
cp build*/PPSSPPHeadless ppsspp/
fi
if [ -e build*/$BUILD_CONFIGURATION/PPSSPPUnitTest ]; then
cp build*/$BUILD_CONFIGURATION/PPSSPPUnitTest ppsspp/
elif [ -e build*/PPSSPPUnitTest ]; then
cp build*/PPSSPPUnitTest ppsspp/
fi
- name: Upload build
uses: actions/upload-artifact@v7
if: matrix.extra == 'test'
with:
name: ${{ matrix.os }} build
path: ppsspp/
- name: Upload iOS build
uses: actions/upload-artifact@v7
if: matrix.id == 'ios'
with:
name: ${{ matrix.id }} build
path: ppsspp/
- name: Create macOS release
if: github.ref_type == 'tag' && matrix.id == 'macos'
working-directory: ppsspp
run: mv PPSSPPSDL.zip PPSSPPSDL-macOS-${GITHUB_REF_NAME}.zip
- name: Upload macOS & iOS release
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
if: github.ref_type == 'tag' && (matrix.id == 'macos' || matrix.id == 'ios')
with:
files: |
ppsspp/*.zip
ppsspp/*.ipa
ppsspp/*.deb
body: >
PPSSPP is a cross-platform PSP emulator.
Visit PPSSPP [official website](https://ppsspp.org)
for a [full changelog](https://ppsspp.org/index.html#news)
as well as the [downloads section](https://ppsspp.org/downloads.html)
for other platforms.
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-26.04, macos-latest]
runs-on: ${{ matrix.os }}
needs: build
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
with:
submodules: false
- name: Fetch tests
working-directory: ${{ env.GITHUB_WORKSPACE }}
# Doing this to avoid ffmpeg and other large submodules.
run: git submodule update --init pspautotests frametests
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update -y -qq
sudo apt-get install libsdl3-dev libgl1-mesa-dev libglu1-mesa-dev libsdl3-ttf-dev libfontconfig1-dev libcurl4-openssl-dev
- name: Install macOS dependencies
if: runner.os == 'macOS'
run: brew install sdl3 sdl3_ttf
- name: Download build
uses: actions/download-artifact@v8
with:
name: ${{ matrix.os }} build
path: ppsspp/
# Not sure where it's ending up, but test.py can't find it...
- name: Fix headless permissions
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
cp `find . -name PPSSPPHeadless` .
chmod +x PPSSPPHeadless
cp `find . -name PPSSPPUnitTest` .
chmod +x PPSSPPUnitTest
- name: Execute unit tests
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: ./PPSSPPUnitTest ALL
- name: Execute headless tests
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: python test.py -g --graphics=software
- name: Execute frametests
if: runner.os == 'Linux'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: python3 frametests.py frametests/frametests.json --out-mode=failures
- name: Upload frametest report
uses: actions/upload-artifact@v7
if: runner.os == 'Linux' && always()
with:
name: frametest-report
path: frametests/out/
test-headless-alpine:
runs-on: ubuntu-latest
container:
image: alpine:latest
options: --shm-size=8g
steps:
- name: Install Linux dependencies (Alpine)
run: |
apk add build-base wget git bash cmake python3 glu-dev sdl3-dev sdl3_ttf-dev curl-dev
- uses: actions/checkout@v7
with:
submodules: recursive
- name: Fix git detected dubious ownership in repository
run: |
chown -R $(id -u):$(id -g) $PWD
- name: Setup ccache
uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23
- name: Compile ffmpeg
run: |
cd ffmpeg && ./linux_x86-64.sh
- name: Build for testing
run: |
./b.sh --headless --unittest
- name: Execute unit tests
run: |
./build/PPSSPPUnitTest ALL
- name: Execute headless tests
run: |
python test.py -g --graphics=software