Skip to content

[CPU/XThread] Add DWARF .eh_frame unwind info for JIT code on Linux #579

[CPU/XThread] Add DWARF .eh_frame unwind info for JIT code on Linux

[CPU/XThread] Add DWARF .eh_frame unwind info for JIT code on Linux #579

Workflow file for this run

name: CI
on:
push:
paths-ignore:
- '*.md'
- 'docs/**'
- 'LICENSE'
pull_request:
paths-ignore:
- '*.md'
- 'docs/**'
- 'LICENSE'
workflow_dispatch:
jobs:
lint:
name: Lint
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@main
- name: Setup
env:
LLVM_VERSION: 21
run: |
UBUNTU_BASE=$(lsb_release -cs)
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-$LLVM_VERSION main"
sudo apt-get -y update
sudo apt-get -y install clang-format-$LLVM_VERSION
- name: Lint
run: ./xenia-build.py lint --all
build-linux:
name: Build Linux
needs: lint
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@main
with:
fetch-depth: 0
- name: Cache premake5
id: cache-premake5
uses: actions/cache@main
with:
path: tools/build/bin/premake5
key: ${{ runner.os }}-premake5-${{ hashFiles('third_party/premake-core/**') }}
- name: Cache Qt6
id: cache-qt-linux
uses: actions/cache@v3
with:
path: /opt/Qt
key: ${{ runner.os }}-qt6-6.10.1
restore-keys: |
${{ runner.os }}-qt6-
- name: Cache linuxdeploy tools
id: cache-linuxdeploy
uses: actions/cache@v3
with:
path: ~/linuxdeploy
key: ${{ runner.os }}-linuxdeploy-tools
restore-keys: |
${{ runner.os }}-linuxdeploy-
- name: Cache submodules
id: cache-submodules
uses: actions/cache@v3
with:
path: third_party
key: ${{ runner.os }}-submodules-${{ hashFiles('.gitmodules') }}-${{ hashFiles('.git/modules/third_party/*/HEAD') }}
- name: Cache Vulkan SDK
id: cache-vulkan-sdk-linux
uses: actions/cache@v3
with:
path: ~/vulkan-sdk
key: ${{ runner.os }}-vulkan-sdk-latest
- name: Setup
run: |
UBUNTU_BASE=$(lsb_release -cs)
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-21 main"
sudo apt-get -y update
sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libsdl2-dev libvulkan-dev libx11-xcb-dev clang-21 ninja-build spirv-tools libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-cursor0 libxcb-shape0 libfontconfig1-dev libxtst-dev
# Install Vulkan SDK
if [ '${{ steps.cache-vulkan-sdk-linux.outputs.cache-hit }}' != 'true' ]; then
wget -qO vulkan-sdk.tar.xz https://sdk.lunarg.com/sdk/download/latest/linux/vulkan-sdk.tar.xz
mkdir -p ~/vulkan-sdk
tar -xf vulkan-sdk.tar.xz -C ~/vulkan-sdk
fi
VULKAN_SDK_VERSION=$(ls ~/vulkan-sdk)
echo "VULKAN_SDK=$HOME/vulkan-sdk/$VULKAN_SDK_VERSION/x86_64" >> $GITHUB_ENV
echo "$HOME/vulkan-sdk/$VULKAN_SDK_VERSION/x86_64/bin" >> $GITHUB_PATH
# Install Qt 6.10.1 via aqtinstall
if [ '${{ steps.cache-qt-linux.outputs.cache-hit }}' != 'true' ]; then
pip install aqtinstall
echo "Available architectures for Qt 6.10.1:"
aqt list-qt linux desktop --arch 6.10.1 || true
aqt install-qt linux desktop 6.10.1 linux_gcc_64 -O /opt/Qt
fi
export PATH="/opt/Qt/6.10.1/gcc_64/bin:$PATH"
export CMAKE_PREFIX_PATH="/opt/Qt/6.10.1/gcc_64"
export PKG_CONFIG_PATH="/opt/Qt/6.10.1/gcc_64/lib/pkgconfig:$PKG_CONFIG_PATH"
export QT_DIR="/opt/Qt/6.10.1/gcc_64"
echo "/opt/Qt/6.10.1/gcc_64/bin" >> $GITHUB_PATH
echo "CMAKE_PREFIX_PATH=/opt/Qt/6.10.1/gcc_64" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=/opt/Qt/6.10.1/gcc_64/lib/pkgconfig" >> $GITHUB_ENV
echo "QT_DIR=/opt/Qt/6.10.1/gcc_64" >> $GITHUB_ENV
# Download linuxdeploy tools if not cached
if [ '${{ steps.cache-linuxdeploy.outputs.cache-hit }}' != 'true' ]; then
mkdir -p ~/linuxdeploy
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage -O ~/linuxdeploy/linuxdeploy
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage -O ~/linuxdeploy/linuxdeploy-plugin-qt
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage -O ~/linuxdeploy/linuxdeploy-plugin-appimage
chmod +x ~/linuxdeploy/linuxdeploy ~/linuxdeploy/linuxdeploy-plugin-qt ~/linuxdeploy/linuxdeploy-plugin-appimage
fi
echo "$HOME/linuxdeploy" >> $GITHUB_PATH
# Verify shader tools are available
which glslangValidator && glslangValidator --version || echo "Warning: glslangValidator not found"
which spirv-opt && spirv-opt --version || echo "Warning: spirv-opt not found"
which spirv-dis || echo "Warning: spirv-dis not found"
# Update submodules if not cached
if [ '${{ steps.cache-submodules.outputs.cache-hit }}' != 'true' ]; then
git submodule update --init --depth=1 -j$(getconf _NPROCESSORS_ONLN) $(grep -oP '(?<=path = )(?!third_party\/(DirectXShaderCompiler|premake-(androidndk|export-compile-commands))).+' .gitmodules)
fi
if [ '${{ steps.cache-premake5.outputs.cache-hit }}' != 'true' ]; then
./xenia-build.py premake
cp third_party/premake-core/bin/release/premake5 tools/build/bin
fi
# Fetch data repos (game-patches, optimized-settings)
./xenia-build.py fetchdata
- name: Build
env:
CC: clang-21
CXX: clang++-21
run: ./xenia-build.py build --config=Release
- name: Prepare artifacts
id: prepare_artifacts
run: |
binary=build/bin/Linux/Release/xenia_edge
if [ $(stat -c%s $binary) -le 100000 ]; then
echo "::error::Binary is too small."
fi
chmod +x $binary
mkdir -p artifacts/xenia_edge
# Use linuxdeploy to bundle Qt dependencies
export QMAKE=/opt/Qt/6.10.1/gcc_64/bin/qmake
export LD_LIBRARY_PATH=/opt/Qt/6.10.1/gcc_64/lib:$LD_LIBRARY_PATH
# Install icons with proper naming for linuxdeploy
mkdir -p artifacts/xenia_edge/usr/share/icons/hicolor/16x16/apps
mkdir -p artifacts/xenia_edge/usr/share/icons/hicolor/32x32/apps
mkdir -p artifacts/xenia_edge/usr/share/icons/hicolor/48x48/apps
mkdir -p artifacts/xenia_edge/usr/share/icons/hicolor/64x64/apps
mkdir -p artifacts/xenia_edge/usr/share/icons/hicolor/128x128/apps
mkdir -p artifacts/xenia_edge/usr/share/icons/hicolor/256x256/apps
mkdir -p artifacts/xenia_edge/usr/share/icons/hicolor/512x512/apps
mkdir -p artifacts/xenia_edge/usr/share/icons/hicolor/1024x1024/apps
cp assets/icon/16.png artifacts/xenia_edge/usr/share/icons/hicolor/16x16/apps/xenia_edge.png
cp assets/icon/32.png artifacts/xenia_edge/usr/share/icons/hicolor/32x32/apps/xenia_edge.png
cp assets/icon/48.png artifacts/xenia_edge/usr/share/icons/hicolor/48x48/apps/xenia_edge.png
cp assets/icon/64.png artifacts/xenia_edge/usr/share/icons/hicolor/64x64/apps/xenia_edge.png
cp assets/icon/128.png artifacts/xenia_edge/usr/share/icons/hicolor/128x128/apps/xenia_edge.png
cp assets/icon/256.png artifacts/xenia_edge/usr/share/icons/hicolor/256x256/apps/xenia_edge.png
cp assets/icon/512.png artifacts/xenia_edge/usr/share/icons/hicolor/512x512/apps/xenia_edge.png
cp assets/icon/1024.png artifacts/xenia_edge/usr/share/icons/hicolor/1024x1024/apps/xenia_edge.png
# Copy all necessary files (excluding build artifacts) next to the binary in AppDir
mkdir -p artifacts/xenia_edge/usr/bin
# Copy directories (optimized_settings, game_patches, etc.)
find build/bin/Linux/Release -maxdepth 1 -type d ! -name Release -exec cp -r {} artifacts/xenia_edge/usr/bin/ \;
# Copy any additional runtime files if needed (currently just directories are copied)
# Run linuxdeploy with Qt plugin to deploy all Qt dependencies and create AppImage
export EXTRA_PLATFORM_PLUGINS="libqwayland.so"
~/linuxdeploy/linuxdeploy --appdir artifacts/xenia_edge \
--executable $binary \
--desktop-file assets/xenia_edge.desktop \
--icon-file assets/icon/256.png \
--plugin qt \
--output appimage
# linuxdeploy creates the AppImage in the current directory
# Find and rename it to a standard name
appimage_file=$(ls -1 *.AppImage | head -n1)
if [ -z "$appimage_file" ]; then
echo "::error::AppImage file not found after linuxdeploy"
exit 1
fi
# Create final artifacts directory and move the AppImage there
mkdir -p artifacts/release
mv "$appimage_file" artifacts/release/xenia_edge.AppImage
chmod +x artifacts/release/xenia_edge.AppImage
# Also copy LICENSE
cp LICENSE artifacts/release/
- name: Upload xenia edge artifacts
if: steps.prepare_artifacts.outcome == 'success'
uses: actions/upload-artifact@main
with:
name: xenia_edge_linux
path: artifacts/release
if-no-files-found: error
build-windows:
name: Build Windows
needs: lint
runs-on: windows-2025
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
steps:
- uses: actions/checkout@main
with:
fetch-depth: 0
submodules: false
- name: Cache Vulkan SDK
id: cache-vulkan-sdk
uses: actions/cache@v3
with:
path: C:\VulkanSDK
key: ${{ runner.os }}-vulkan-sdk-${{ hashFiles('**/vulkan-sdk.exe') }}
restore-keys: |
${{ runner.os }}-vulkan-sdk-
- name: Cache Qt6
id: cache-qt
uses: actions/cache@v3
with:
path: C:\Qt
key: ${{ runner.os }}-qt6-6.10.1
restore-keys: |
${{ runner.os }}-qt6-
- name: Cache submodules
id: cache-submodules
uses: actions/cache@v3
with:
path: third_party
key: ${{ runner.os }}-submodules-${{ hashFiles('.gitmodules') }}-${{ hashFiles('.git/modules/third_party/*/HEAD') }}
- name: Setup
run: |
# Install Vulkan SDK which includes spirv-tools
if (Test-Path -Path "C:\VulkanSDK") {
echo "Vulkan SDK found in cache."
} else {
Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe" -OutFile "vulkan-sdk.exe"
Start-Process -FilePath "vulkan-sdk.exe" -ArgumentList "--accept-licenses", "--default-answer", "--confirm-command", "install" -Wait
}
$env:VULKAN_SDK = "C:\VulkanSDK\$(Get-ChildItem -Path 'C:\VulkanSDK' -Directory | Select-Object -First 1 -ExpandProperty Name)"
$env:PATH = "$env:VULKAN_SDK\Bin;$env:PATH"
echo "VULKAN_SDK=$env:VULKAN_SDK" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "$env:VULKAN_SDK\Bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
# Verify shader tools are available
$spirvOptPath = "$env:VULKAN_SDK\Bin\spirv-opt.exe"
if (Test-Path $spirvOptPath) {
& $spirvOptPath --version
echo "spirv-opt found at: $spirvOptPath"
} else {
echo "Warning: spirv-opt.exe not found at expected location"
}
$glslangPath = "$env:VULKAN_SDK\Bin\glslangValidator.exe"
if (Test-Path $glslangPath) {
& $glslangPath --version
echo "glslangValidator found at: $glslangPath"
} else {
echo "Warning: glslangValidator.exe not found at expected location"
}
$spirvDisPath = "$env:VULKAN_SDK\Bin\spirv-dis.exe"
if (Test-Path $spirvDisPath) {
echo "spirv-dis found at: $spirvDisPath"
} else {
echo "Warning: spirv-dis.exe not found at expected location"
}
# Verify FXC is available (from Windows SDK)
$fxcPaths = Get-ChildItem -Path "${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64\fxc.exe" -ErrorAction SilentlyContinue | Sort-Object FullName
if ($fxcPaths) {
$fxcPath = $fxcPaths[-1].FullName
echo "FXC found at: $fxcPath"
} else {
echo "Warning: fxc.exe not found in Windows SDK"
}
# Install Qt6
$qtCacheHit = '${{ steps.cache-qt.outputs.cache-hit }}'
if ($qtCacheHit -ne 'true') {
pip install aqtinstall
aqt install-qt windows desktop 6.10.1 win64_msvc2022_64 -O C:\Qt
}
$cacheHit = '${{ steps.cache-submodules.outputs.cache-hit }}'
if ($cacheHit -ne 'true') {
git submodule update --init --depth=1 -j $env:NUMBER_OF_PROCESSORS (Select-String -CaseSensitive '(?<=path = )(?!third_party\/(premake-(androidndk|cmake|export-compile-commands))).+' .gitmodules).Matches.Value
}
# Fetch data repos (game-patches, optimized-settings)
python xenia-build.py fetchdata
- name: Build
run: python xenia-build.py build --config=Release --target=xenia-app
- name: Prepare artifacts
id: prepare_artifacts
run: |
$binary = 'build\bin\Windows\Release\xenia_edge.exe'
if ((get-item $binary).Length -le 100000) {
echo "::error::$binary is too small."
}
robocopy . build\bin\Windows\Release LICENSE /r:0 /w:0
# Copy all files and directories (Qt DLLs, plugins, etc.) excluding build artifacts
robocopy build\bin\Windows\Release artifacts\xenia_edge /MIR /r:0 /w:0 /XF *.lib *.idb *.exp /XD generic iconengines imageformats networkinformation styles tls
If ($LastExitCode -le 7) { echo "LastExitCode = $LastExitCode";$LastExitCode = 0 }
- name: Upload xenia edge artifacts
if: steps.prepare_artifacts.outcome == 'success'
uses: actions/upload-artifact@main
with:
name: xenia_edge_windows
path: artifacts\xenia_edge
if-no-files-found: error
release:
name: Create Release
needs: [build-linux, build-windows]
runs-on: ubuntu-latest
if: |
github.repository == 'has207/xenia-edge' &&
github.event_name == 'push' &&
github.ref == 'refs/heads/edge'
steps:
- name: Download Linux artifacts
uses: actions/download-artifact@main
with:
name: xenia_edge_linux
path: linux_artifacts
- name: Download Windows artifacts
uses: actions/download-artifact@main
with:
name: xenia_edge_windows
path: windows_artifacts
- name: Create Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
run: |
# Create zips
cd linux_artifacts
# For Linux, just rename the AppImage (no need to zip a single file)
mv xenia_edge.AppImage ../xenia_edge_linux.AppImage
cd ../windows_artifacts
7z a ../xenia_edge_windows.zip * -xr!'*.pdb' -mx9 -bb3
cd ..
# Create release
tag=${GITHUB_SHA::7}
gh release create $tag xenia_edge_linux.AppImage xenia_edge_windows.zip \
--target $GITHUB_SHA -t "xenia_edge" --generate-notes