Initial CI setup with Discord notifications and updated repository links

This repository builds upon the excellent work of previous contributors:
- pkgforge-dev for the original Citron AppImage build scripts and infrastructure
- CollectingW for the Citron-Nightly build workflows and automation

Changes made in this commit:
- Updated all repository links from pkgforge-dev/Citron-AppImage and
  CollectingW/Citron-Nightly to Zephyron-Dev/Citron-CI
- Added Discord webhook notifications for successful builds (Android, Linux, Windows)
- Integrated automated notifications with build metadata (version, date, download links)

Build workflows included:
- Android: Daily APK builds for arm64-v8a
- Linux: Multiple variants (x86_64, x86_64_v3, PGO optimized) as AppImages
- Windows: x64 builds with Qt6 support

All builds run daily at 12 AM UTC and can be triggered manually via workflow_dispatch.
This commit is contained in:
Zephyron-Dev
2025-10-16 18:55:27 +10:00
commit b147f71e50
11 changed files with 1455 additions and 0 deletions
+131
View File
@@ -0,0 +1,131 @@
name: Build Citron (Android)
on:
workflow_dispatch:
schedule:
- cron: "0 12 * * *"
jobs:
build-android:
name: Build Android APK
runs-on: ubuntu-24.04
outputs:
git_hash: ${{ steps.get_hash.outputs.git_hash }}
steps:
- name: Clone Citron Source Code
run: git clone --recursive --depth 1 https://git.citron-emu.org/citron/emulator.git citron_source
- name: Clean and Force-Update Submodules
working-directory: ./citron_source
run: |
git submodule deinit --all --force
git submodule update --init --recursive --force
- name: Get Citron Commit Hash
id: get_hash
working-directory: ./citron_source
run: echo "git_hash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Install system dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq wget unzip curl git cmake build-essential pkg-config zip glslang-tools
- name: Install Android SDK
run: |
wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
unzip -q commandlinetools-linux-11076708_latest.zip
mkdir -p android-sdk/cmdline-tools
mv cmdline-tools android-sdk/cmdline-tools/latest
echo "ANDROID_HOME=$PWD/android-sdk" >> $GITHUB_ENV
echo "$PWD/android-sdk/cmdline-tools/latest/bin" >> $GITHUB_PATH
- name: Accept Android SDK licenses and install components
run: |
yes | sdkmanager --licenses > /dev/null || true
sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0"
- name: Install Android NDK
run: |
wget -q https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
unzip -q android-ndk-r26b-linux.zip
echo "ANDROID_NDK_HOME=$PWD/android-ndk-r26b" >> $GITHUB_ENV
- name: Configure CMake
run: |
cmake -B build-android -S citron_source \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-30 \
-DENABLE_QT=OFF \
-DENABLE_SDL2=OFF \
-DENABLE_WEB_SERVICE=OFF \
-DCITRON_USE_BUNDLED_VCPKG=ON \
-DCITRON_USE_BUNDLED_FFMPEG=ON \
-DANDROID_ARM_NEON=ON \
-DCITRON_ENABLE_LTO=ON
- name: Build with CMake
run: |
cmake --build build-android --config Release --parallel $(nproc)
- name: Build APK with Gradle
run: |
cd citron_source/src/android
export ANDROID_SDK_ROOT="$ANDROID_HOME"
./gradlew assembleMainlineRelease
- name: Upload APK artifact
uses: actions/upload-artifact@v4
with:
name: citron-android-nightly
path: citron_source/src/android/app/build/outputs/apk/mainline/release/*.apk
release-android:
name: "Release Android Nightly"
needs: [build-android]
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Download APK artifact
uses: actions/download-artifact@v4
with:
name: citron-android-nightly
path: .
- name: Get version info for release name
shell: bash
run: |
echo "DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
echo "GIT_HASH=${{ needs.build-android.outputs.git_hash }}" >> $GITHUB_ENV
- name: Delete previous nightly release and tag
run: gh release delete "nightly-android" --repo "${{ github.repository }}" --cleanup-tag -y || true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create new nightly release
uses: softprops/action-gh-release@v2
with:
name: "Continuous Build: (Android Nightly: ${{ env.GIT_HASH }})"
tag_name: "nightly-android"
prerelease: true
files: "*.apk"
- name: Post to Discord
if: success()
run: |
DOWNLOAD_URL="https://github.com/${{ github.repository }}/releases/tag/nightly-android"
curl -H "Content-Type: application/json" \
-d "{\"content\":\"🤖 **New Android Build Available!**\n\n📦 **Version:** \`${{ env.GIT_HASH }}\`\n📅 **Date:** ${{ env.DATE }}\n🔗 **Download:** $DOWNLOAD_URL\"}" \
https://discord.com/api/webhooks/1428304731809517588/fG7t7MBprKFss5oGcI05DIFM3JdO41Z0juSV_zOfb9K-UTvyI2fd3-Ciwi48npWXYHLb
+140
View File
@@ -0,0 +1,140 @@
name: Build Citron (Linux)
concurrency:
group: build-nightly-${{ github.ref }}
cancel-in-progress: true
on:
schedule:
- cron: "0 12 * * *"
workflow_dispatch: {}
jobs:
build:
name: "${{ matrix.name }}"
runs-on: ${{ matrix.os }} # Use matrix to select the runner
timeout-minutes: 120
strategy:
fail-fast: false # Allows all matrix jobs to complete
matrix:
include:
# --- x86_64 Builds ---
- name: "Citron Build (Normal x86_64)"
os: ubuntu-latest
arch_suffix: ""
build_arg: ""
- name: "Citron Build (Optimized x86_64)"
os: ubuntu-latest
arch_suffix: "_v3"
build_arg: "v3"
- name: "Citron Build (Normal PGO x86_64)"
os: ubuntu-latest
arch_suffix: "_pgo"
build_arg: "pgo"
- name: "Citron Build (Optimized PGO x86_64)"
os: ubuntu-latest
arch_suffix: "_v3_pgo"
build_arg: "v3-pgo"
container: ghcr.io/pkgforge-dev/archlinux:latest
steps:
- name: Install Git
run: pacman -Syu --noconfirm --needed git
- name: Checkout Workflow Scripts
uses: actions/checkout@v4
- name: Checkout Upstream Source Code
run: git clone --recurse-submodules https://git.citron-emu.org/citron/emulator.git emulator
- name: Prepare Build Environment
run: |
mv get-dependencies.sh emulator/
mv build-citron.sh emulator/
mv package-citron.sh emulator/
- name: Add Git Safe Directory
working-directory: ./emulator
run: git config --global --add safe.directory "$PWD"
- name: Install dependencies
working-directory: ./emulator
run: chmod +x ./get-dependencies.sh && ./get-dependencies.sh
- name: Build Citron from source
working-directory: ./emulator
run: |
NPROC_VAL=$(nproc --all)
JOBS_VAL=$((NPROC_VAL > 4 ? 4 : NPROC_VAL))
chmod +x ./build-citron.sh
JOBS=${JOBS_VAL} DEVEL=true ./build-citron.sh ${{ matrix.build_arg }}
- name: Package AppImage with Correct Name
working-directory: ./emulator
run: |
GIT_SHA=$(git rev-parse --short HEAD)
export APP_VERSION="${GIT_SHA}"
export VERSION="${GIT_SHA}"
export ARCH_SUFFIX="${{ matrix.arch_suffix }}"
export DEVEL="true"
chmod +x ./package-citron.sh
./package-citron.sh
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: Artifacts${{ matrix.arch_suffix }}
path: emulator/dist/
release:
if: ${{ github.ref_name == 'main' }}
name: "release"
needs: [build]
permissions:
actions: read
security-events: write
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout Upstream Repository
run: git clone https://git.citron-emu.org/citron/emulator.git .
- name: Set Version
id: version
run: echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
pattern: Artifacts*
merge-multiple: true
path: .
- name: Del Previous Release
run: gh release delete "nightly-linux" --repo "${GITHUB_REPOSITORY}" --cleanup-tag -y && sleep 5
env:
GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
continue-on-error: true
- uses: softprops/action-gh-release@v2
with:
name: "Continuous Build (Linux Nightly: ${{ steps.version.outputs.sha }})"
tag_name: "nightly-linux"
prerelease: true
draft: false
generate_release_notes: false
make_latest: false
files: |
*.AppImage*
*.tar.zst
- name: Post to Discord
if: success()
run: |
DOWNLOAD_URL="https://github.com/${{ github.repository }}/releases/tag/nightly-linux"
DATE=$(date +'%Y-%m-%d')
curl -H "Content-Type: application/json" \
-d "{\"content\":\"🐧 **New Linux Build Available!**\n\n📦 **Version:** \`${{ steps.version.outputs.sha }}\`\n📅 **Date:** ${DATE}\n🔗 **Download:** $DOWNLOAD_URL\n\n✨ Includes x86_64, x86_64_v3, PGO builds\"}" \
https://discord.com/api/webhooks/1428304731809517588/fG7t7MBprKFss5oGcI05DIFM3JdO41Z0juSV_zOfb9K-UTvyI2fd3-Ciwi48npWXYHLb
+111
View File
@@ -0,0 +1,111 @@
name: Build Citron (Windows)
concurrency:
group: build-windows-nightly-${{ github.ref }}
cancel-in-progress: true
on:
schedule:
- cron: "0 12 * * *"
workflow_dispatch: {}
jobs:
build:
name: "Citron Build (Windows)"
runs-on: windows-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Vulkan SDK
shell: pwsh
run: |
$vulkan_sdk_url = "https://sdk.lunarg.com/sdk/download/1.3.283.0/windows/VulkanSDK-1.3.283.0-Installer.exe"
Invoke-WebRequest -Uri $vulkan_sdk_url -OutFile VulkanSDK-Installer.exe
Start-Process -FilePath ".\VulkanSDK-Installer.exe" -ArgumentList "--accept-licenses", "--default-answer", "--confirm-command", "install" -Wait
echo "C:\VulkanSDK\1.3.283.0\Bin" | Out-File -FilePath $env:GITHUB_PATH -Append
- name: Clone Citron Source
shell: bash
run: git clone --recursive "https://git.citron-emu.org/citron/emulator.git" citron
- name: Get Nightly Version
id: version
working-directory: ./citron
shell: bash
run: |
git fetch --tags
VERSION=$(git rev-parse --short HEAD)
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
- name: Configure CMake
working-directory: ./citron
shell: cmd
run: |
cmake -B build -S . -G "Visual Studio 17 2022" -A x64 ^
-DCITRON_USE_BUNDLED_VCPKG=ON ^
-DCITRON_ENABLE_LTO=ON ^
-DCITRON_USE_BUNDLED_QT=ON ^
-DENABLE_QT6=ON ^
-DCITRON_TESTS=OFF ^
-DUSE_DISCORD_PRESENCE=ON
- name: Build Citron
working-directory: ./citron
shell: cmd
run: cmake --build build --config Release --parallel
- name: Package Windows Build
shell: pwsh
run: |
mkdir dist
echo "Creating final zip archive..."
Compress-Archive -Path ".\citron\build\bin\Release\*" -DestinationPath ".\dist\Citron-windows-nightly-${{ steps.version.outputs.VERSION }}.zip"
- name: Upload Windows Build
uses: actions/upload-artifact@v4
with:
name: Citron-Windows-Nightly
path: "dist/*.zip"
release:
if: ${{ github.ref_name == 'main' }}
name: "Release"
needs: [build]
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: Citron-Windows-Nightly
path: .
- name: Get Version from Filename
shell: bash
run: |
FILENAME=$(ls *.zip)
VERSION=${FILENAME#Citron-windows-nightly-}
VERSION=${VERSION%.zip}
echo "APP_VERSION=${VERSION}" >> $GITHUB_ENV
- name: Delete Previous Release
run: gh release delete "nightly-windows" --repo "${{ github.repository }}" --cleanup-tag -y || true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release Artifacts
uses: softprops/action-gh-release@v2
with:
name: "Continuous Build (Windows Nightly: ${{ env.APP_VERSION }})"
tag_name: "nightly-windows"
prerelease: true
files: "*.zip"
- name: Post to Discord
if: success()
run: |
DOWNLOAD_URL="https://github.com/${{ github.repository }}/releases/tag/nightly-windows"
DATE=$(date +'%Y-%m-%d')
curl -H "Content-Type: application/json" \
-d "{\"content\":\"🪟 **New Windows Build Available!**\n\n📦 **Version:** \`${{ env.APP_VERSION }}\`\n📅 **Date:** ${DATE}\n🔗 **Download:** $DOWNLOAD_URL\"}" \
https://discord.com/api/webhooks/1428304731809517588/fG7t7MBprKFss5oGcI05DIFM3JdO41Z0juSV_zOfb9K-UTvyI2fd3-Ciwi48npWXYHLb
+38
View File
@@ -0,0 +1,38 @@
---
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-executables-have-shebangs
- id: check-merge-conflict
- id: check-shebang-scripts-are-executable
- id: fix-byte-order-marker
- id: mixed-line-ending
- id: end-of-file-fixer
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
- id: check-yaml
- id: no-commit-to-branch
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
- id: shellcheck
args: ["--severity=error"]
- repo: https://github.com/scop/pre-commit-shfmt
rev: v3.10.0-2
hooks:
- id: shfmt
args: ["-w", "-s"]
- repo: https://github.com/rhysd/actionlint
rev: v1.7.6
hooks:
- id: actionlint
- repo: https://github.com/woodruffw/zizmor
rev: v0.8.0
hooks:
- id: zizmor
files: ^\.github/workflows/.*\.ya?ml$
+1
View File
@@ -0,0 +1 @@
0.8.0
+674
View File
File diff suppressed because it is too large Load Diff
+69
View File
@@ -0,0 +1,69 @@
# Maintainer: Collecting <collecting@citron-emu.org>
# The '-git' suffix signifies this is a bleeding-edge build from the git repo
pkgname=citron-git
pkgver=0.1.r0.g1a2b3c4 # This will be replaced by the pkgver() function
pkgrel=1
pkgdesc="A Nintendo Switch emulator"
arch=('x86_64' 'aarch64')
url="https://citron-emu.org/"
license=('GPL2')
# Dependencies needed to run the emulator
depends=(
'boost-libs' 'enet' 'fmt' 'ffmpeg' 'gamemode' 'glslang' 'hicolor-icon-theme'
'libdecor' 'libxkbcommon-x11' 'mbedtls2' 'nlohmann-json' 'qt6-base'
'qt6-multimedia' 'sdl2' 'vulkan-icd-loader'
)
# Dependencies needed only to build the emulator from source
makedepends=(
'boost' 'catch2' 'cmake' 'git' 'ninja' 'nasm' 'qt6-tools' 'vulkan-headers'
)
# This points to the source code repository
source=("git+https://git.citron-emu.org/citron/emulator.git")
sha256sums=('SKIP')
# This function automatically generates a version string based on the latest git commit
pkgver() {
cd "$pkgname"
git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
}
# This function runs before the build and is used to apply patches
prepare() {
cd "$pkgname"
# Apply compatibility patches for newer Boost versions
find . -type f \( -name '*.cpp' -o -name '*.h' \) | xargs sed -i 's/\bboost::asio::io_service\b/boost::asio::io_context/g'
find . -type f \( -name '*.cpp' -o -name '*.h' \) | xargs sed -i 's/\bboost::asio::io_service::strand\b/boost::asio::strand<boost::asio::io_context::executor_type>/g'
find . -type f \( -name '*.cpp' -o -name '*.h' \) | xargs sed -i 's|#include *<boost/process/async_pipe.hpp>|#include <boost/process/v1/async_pipe.hpp>|g'
find . -type f \( -name '*.cpp' -o -name '*.h' \) | xargs sed -i 's/\bboost::process::async_pipe\b/boost::process::v1::async_pipe/g'
}
# This function contains the build commands
build() {
cd "$pkgname"
# makepkg sets CFLAGS and CXXFLAGS, so we don't need to specify arch flags
cmake -B build -S . -GNinja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCITRON_USE_BUNDLED_VCPKG=OFF \
-DCITRON_USE_BUNDLED_QT=OFF \
-DUSE_SYSTEM_QT=ON \
-DCITRON_USE_BUNDLED_FFMPEG=OFF \
-DCITRON_USE_BUNDLED_SDL2=OFF \
-DCITRON_TESTS=OFF \
-DCITRON_CHECK_SUBMODULES=OFF \
-DCITRON_ENABLE_LTO=ON \
-DCITRON_USE_QT_MULTIMEDIA=ON \
-DENABLE_QT_TRANSLATION=ON
ninja -C build
}
# This function installs the built files into a temporary directory
package() {
cd "$pkgname"
DESTDIR="$pkgdir/" ninja -C build install
}
+47
View File
@@ -0,0 +1,47 @@
# Citron-Nightly 🐧
[![GitHub Downloads](https://img.shields.io/github/downloads/Zephyron-Dev/Citron-CI/total?logo=github&label=GitHub%20Downloads)](https://github.com/Zephyron-Dev/Citron-CI/releases/latest)
[![CI Build Status](https://github.com/Zephyron-Dev/Citron-CI/actions/workflows/build-stable.yml/badge.svg)](https://github.com/Zephyron-Dev/Citron-CI/releases/latest)
This repository makes Nightly builds for **x86_64** (generic) and **x86_64_v3** on Linux, and also Windows & Android builds! If your CPU is less than 10 years old, for Linux, use the x86_64_v3 build since it has a significant performance boost. These builds are all produced @ 12 AM UTC every single day.
* [Latest Commits Can Be Found Here](https://git.citron-emu.org/citron/emulator/-/commits/f3374ea7e61cb0bba79d17272964717e37935575)
* [Latest Android Nightly Release](https://github.com/Zephyron-Dev/Citron-CI/releases/tag/nightly-android)
* [Latest Linux Nightly Release](https://github.com/Zephyron-Dev/Citron-CI/releases/tag/nightly-linux)
* [Latest Windows Nightly Release](https://github.com/Zephyron-Dev/Citron-CI/releases/tag/nightly-windows)
# READ THIS IF YOU HAVE ISSUES
If you are on wayland (specially GNOME wayland) and get freezes or crahes you are likely affected by this issue that affects all Qt6 apps: https://github.com/Zephyron-Dev/Citron-CI/issues/50
To fix it simply set the env variable `QT_QPA_PLATFORM=xcb`
---
**Looking for AppImages of other emulators? Check:** [AnyLinux-AppImages](https://pkgforge-dev.github.io/Anylinux-AppImages/)
----
AppImage made using [sharun](https://github.com/VHSgunzo/sharun), which makes it extremely easy to turn any binary into a portable package without using containers or similar tricks.
**This AppImage bundles everything and should work on any linux distro, even on musl based ones.**
It is possible that this appimage may fail to work with appimagelauncher, I recommend these alternatives instead:
* [AM](https://github.com/ivan-hc/AM) `am -i citron` or `appman -i citron`
* [dbin](https://github.com/xplshn/dbin) `dbin install citron.appimage`
* [soar](https://github.com/pkgforge/soar) `soar install citron`
This appimage works without fuse2 as it can use fuse3 instead, it can also work without fuse at all thanks to the [uruntime](https://github.com/VHSgunzo/uruntime)
<details>
<summary><b><i>raison d'être</i></b></summary>
<img src="https://github.com/user-attachments/assets/d40067a6-37d2-4784-927c-2c7f7cc6104b" alt="Inspiration Image">
</a>
</details>
+124
View File
@@ -0,0 +1,124 @@
#!/bin/sh
set -ex
ARCH="${ARCH:-$(uname -m)}"
BUILD_PGO=false
if [ "$1" = 'v3-pgo' ] && [ "$ARCH" = 'x86_64' ]; then
ARCH_FLAGS="-march=x86-64-v3 -O3 -USuccess -UNone -fuse-ld=lld"
BUILD_PGO=true
elif [ "$1" = 'pgo' ] && [ "$ARCH" = 'x86_64' ]; then
ARCH_FLAGS="-march=x86-64 -mtune=generic -O3 -USuccess -UNone -fuse-ld=lld"
BUILD_PGO=true
elif [ "$1" = 'v3' ] && [ "$ARCH" = 'x86_64' ]; then
ARCH_FLAGS="-march=x86-64-v3 -O3 -USuccess -UNone -fuse-ld=lld"
elif [ "$ARCH" = 'x86_64' ]; then
ARCH_FLAGS="-march=x86-64 -mtune=generic -O3 -USuccess -UNone -fuse-ld=lld"
else
ARCH_FLAGS="-march=armv8-a -mtune=generic -O3 -USuccess -UNone -fuse-ld=lld"
fi
git clone --recursive "https://git.citron-emu.org/citron/emulator.git" ./citron
cd ./citron
if [ "$DEVEL" = 'true' ]; then
CITRON_TAG="$(git rev-parse --short HEAD)"
VERSION="$CITRON_TAG"
else
CITRON_TAG=$(git describe --tags)
git checkout "$CITRON_TAG"
VERSION="$(echo "$CITRON_TAG" | awk -F'-' '{print $1}')"
fi
find . -type f \( -name '*.cpp' -o -name '*.h' \) | xargs sed -i 's/\bboost::asio::io_service\b/boost::asio::io_context/g'
find . -type f \( -name '*.cpp' -o -name '*.h' \) | xargs sed -i 's/\bboost::asio::io_service::strand\b/boost::asio::strand<boost::asio::io_context::executor_type>/g'
find . -type f \( -name '*.cpp' -o -name '*.h' \) | xargs sed -i 's|#include *<boost/process/async_pipe.hpp>|#include <boost/process/v1/async_pipe.hpp>|g'
find . -type f \( -name '*.cpp' -o -name '*.h' \) | xargs sed -i 's/\bboost::process::async_pipe\b/boost::process::v1::async_pipe/g'
sed -i '/sse2neon/d' ./src/video_core/CMakeLists.txt
sed -i '/sse2neon/d' ./src/video_core/CMakeLists.txt
sed -i 's/cmake_minimum_required(VERSION 2.8)/cmake_minimum_required(VERSION 3.5)/' externals/xbyak/CMakeLists.txt
HEADER_PATH=$(pacman -Ql qt6-base | grep 'qpa/qplatformnativeinterface.h$' | awk '{print $2}')
if [ -z "$HEADER_PATH" ]; then
echo "ERROR: Could not find qplatformnativeinterface.h path." >&2
exit 1
fi
QT_PRIVATE_INCLUDE_DIR=$(dirname "$(dirname "$HEADER_PATH")")
CXX_FLAGS_EXTRA="-I${QT_PRIVATE_INCLUDE_DIR}"
if [ -z "$JOBS" ]; then JOBS=$(nproc --all); fi
if [ "$BUILD_PGO" = true ]; then
# STAGE 1: Build with instrumentation using manual flags for reliability
mkdir build_instrumented && cd build_instrumented
PGO_FLAGS="-fprofile-generate"
cmake .. -GNinja \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DCITRON_USE_BUNDLED_VCPKG=OFF -DCITRON_USE_BUNDLED_QT=OFF -DUSE_SYSTEM_QT=ON -DENABLE_QT6=ON \
-DCITRON_USE_BUNDLED_FFMPEG=OFF -DCITRON_USE_BUNDLED_SDL2=ON -DCITRON_USE_EXTERNAL_SDL2=OFF \
-DCITRON_TESTS=OFF -DCITRON_CHECK_SUBMODULES=OFF -DCITRON_USE_LLVM_DEMANGLE=OFF \
-DCITRON_ENABLE_LTO=ON -DCITRON_USE_QT_MULTIMEDIA=ON -DCITRON_USE_QT_WEB_ENGINE=OFF \
-DENABLE_QT_TRANSLATION=ON -DUSE_DISCORD_PRESENCE=ON -DBUNDLE_SPEEX=ON -DCITRON_USE_FASTER_LD=OFF \
-DCITRON_USE_EXTERNAL_Vulkan_HEADERS=ON -DCITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES=ON \
-DCITRON_ENABLE_UPDATER=OFF -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS $PGO_FLAGS -Wno-error -w ${CXX_FLAGS_EXTRA}" \
-DCMAKE_C_FLAGS="$ARCH_FLAGS $PGO_FLAGS" \
-DCMAKE_SYSTEM_PROCESSOR="$(uname -m)" -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
ninja -j${JOBS}
# STAGE 2: Generate, merge, and copy profile data
echo "Starting instrumented application to generate profile data..."
export LLVM_PROFILE_FILE="${PWD}/citron.profraw"
xvfb-run -a --server-args="-screen 0 1024x768x24" ./bin/citron &
XVFB_PID=$!
echo "Running for 20 seconds to collect data... (PID: $XVFB_PID)"
sleep 20
echo "Stopping application..."
kill -9 $XVFB_PID || true
echo "Application stopped."
llvm-profdata merge -o ./default.profdata "${LLVM_PROFILE_FILE}"
cd .. && rm -rf build && mkdir build
echo "Copying profile data to the final build directory..."
cp build_instrumented/default.profdata build/
cd build
# STAGE 3: Build again using manual flags for reliability
PGO_FLAGS="-fprofile-use=${PWD}/default.profdata"
cmake .. -GNinja \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DCITRON_USE_BUNDLED_VCPKG=OFF -DCITRON_USE_BUNDLED_QT=OFF -DUSE_SYSTEM_QT=ON -DENABLE_QT6=ON \
-DCITRON_USE_BUNDLED_FFMPEG=OFF -DCITRON_USE_BUNDLED_SDL2=ON -DCITRON_USE_EXTERNAL_SDL2=OFF \
-DCITRON_TESTS=OFF -DCITRON_CHECK_SUBMODULES=OFF -DCITRON_USE_LLVM_DEMANGLE=OFF \
-DCITRON_ENABLE_LTO=ON -DCITRON_USE_QT_MULTIMEDIA=ON -DCITRON_USE_QT_WEB_ENGINE=OFF \
-DENABLE_QT_TRANSLATION=ON -DUSE_DISCORD_PRESENCE=ON -DBUNDLE_SPEEX=ON -DCITRON_USE_FASTER_LD=OFF \
-DCITRON_USE_EXTERNAL_Vulkan_HEADERS=ON -DCITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES=ON \
-DCITRON_ENABLE_UPDATER=OFF -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS $PGO_FLAGS -Wno-error -w ${CXX_FLAGS_EXTRA}" \
-DCMAKE_C_FLAGS="$ARCH_FLAGS $PGO_FLAGS" \
-DCMAKE_SYSTEM_PROCESSOR="$(uname -m)" -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
else
# REGULAR BUILD
mkdir build && cd build
cmake .. -GNinja \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DCITRON_USE_BUNDLED_VCPKG=OFF -DCITRON_USE_BUNDLED_QT=OFF -DUSE_SYSTEM_QT=ON -DENABLE_QT6=ON \
-DCITRON_USE_BUNDLED_FFMPEG=OFF -DCITRON_USE_BUNDLED_SDL2=ON -DCITRON_USE_EXTERNAL_SDL2=OFF \
-DCITRON_TESTS=OFF -DCITRON_CHECK_SUBMODULES=OFF -DCITRON_USE_LLVM_DEMANGLE=OFF \
-DCITRON_ENABLE_LTO=ON -DCITRON_USE_QT_MULTIMEDIA=ON -DCITRON_USE_QT_WEB_ENGINE=OFF \
-DENABLE_QT_TRANSLATION=ON -DUSE_DISCORD_PRESENCE=ON -DBUNDLE_SPEEX=ON -DCITRON_USE_FASTER_LD=OFF \
-DCITRON_USE_EXTERNAL_Vulkan_HEADERS=ON -DCITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES=ON \
-DCITRON_ENABLE_UPDATER=OFF -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS -Wno-error -w ${CXX_FLAGS_EXTRA}" \
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
-DCMAKE_SYSTEM_PROCESSOR="$(uname -m)" -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
fi
ninja -j${JOBS}
sudo ninja install
echo "$VERSION" >~/version
+56
View File
@@ -0,0 +1,56 @@
#!/bin/sh
set -ex
ARCH="$(uname -m)"
pacman -Syu --noconfirm --needed \
base-devel \
boost \
boost-libs \
catch2 \
clang \
cmake \
curl \
enet \
fmt \
ffmpeg \
gamemode \
gcc \
git \
glslang \
glu \
hidapi \
libdecor \
libvpx \
libxi \
libxkbcommon-x11 \
libxss \
lld \
llvm \
mbedtls2 \
mesa \
nasm \
ninja \
nlohmann-json \
numactl \
openal \
pulseaudio \
pulseaudio-alsa \
qt6-base \
qt6-networkauth \
qt6-multimedia \
qt6-tools \
qt6-wayland \
qt6-translations \
sdl2 \
unzip \
vulkan-headers \
vulkan-mesa-layers \
wget \
xcb-util-cursor \
xcb-util-image \
xcb-util-renderutil \
xcb-util-wm \
xorg-server-xvfb \
zip \
zsync
+64
View File
@@ -0,0 +1,64 @@
#!/bin/sh
set -ex
ARCH="${ARCH:-$(uname -m)}"
# The VERSION is now passed as an environment variable from the workflow
if [ -z "$APP_VERSION" ]; then
echo "Error: APP_VERSION environment variable is not set."
exit 1
fi
# Construct unique names for the AppImage and tarball based on the build matrix.
OUTNAME_BASE="citron_nightly-${APP_VERSION}-linux-${ARCH}${ARCH_SUFFIX}"
export OUTNAME_APPIMAGE="${OUTNAME_BASE}.AppImage"
export OUTNAME_TAR="${OUTNAME_BASE}.tar.zst"
URUNTIME="https://raw.githubusercontent.com/pkgforge-dev/Anylinux-AppImages/refs/heads/main/useful-tools/uruntime2appimage.sh"
SHARUN="https://raw.githubusercontent.com/pkgforge-dev/Anylinux-AppImages/refs/heads/main/useful-tools/quick-sharun.sh"
export DESKTOP=/usr/share/applications/org.citron_emu.citron.desktop
export ICON=/usr/share/icons/hicolor/scalable/apps/org.citron_emu.citron.svg
export DEPLOY_OPENGL=1
export DEPLOY_VULKAN=1
export DEPLOY_PIPEWIRE=1
wget --retry-connrefused --tries=30 "$SHARUN" -O ./quick-sharun
chmod +x ./quick-sharun
./quick-sharun /usr/bin/citron* /usr/lib/libgamemode.so* /usr/lib/libpulse.so*
echo "Copying Qt translation files..."
mkdir -p ./AppDir/usr/share/qt6
cp -r /usr/share/qt6/translations ./AppDir/usr/share/qt6/
if [ "$DEVEL" = 'true' ]; then
sed -i 's|Name=citron|Name=citron nightly|' ./AppDir/*.desktop
fi
echo 'SHARUN_ALLOW_SYS_VK_ICD=1' > ./AppDir/.env
echo "Creating tar.zst archive..."
(cd AppDir && tar -c --zstd -f ../"$OUTNAME_TAR" usr)
echo "Successfully created $OUTNAME_TAR"
wget --retry-connrefused --tries=30 "$URUNTIME" -O ./uruntime2appimage
chmod +x ./uruntime2appimage
./uruntime2appimage
echo "Renaming versioned AppImage to the final suffixed name: ${OUTNAME_APPIMAGE}..."
SOURCE_APPIMAGE="citron_nightly-${APP_VERSION}-${ARCH}.AppImage"
mv -v "${SOURCE_APPIMAGE}" "${OUTNAME_APPIMAGE}"
mv -v "${SOURCE_APPIMAGE}.zsync" "${OUTNAME_APPIMAGE}.zsync"
mkdir -p ./dist
mv -v ./*.AppImage* ./dist
mv -v ./*.tar.zst ./dist