build(linux): remove obsolete scripts, fix audio deps, and improve AppImage cleanup

Deleted scripts/CI files:
- Remove AppImage-build-debian-inner.sh, ppImage-build-debian.sh, AppImage-build-local.sh: replaced by AppImageBuilder/package-citron-linux.sh
- Remove AppImageBuilder/build.sh, AppImageBuilder/build-v2.sh: superseded by package-citron-linux.sh
- Remove build-for-mingw.bat, build-for-mingw.sh, fix-pgo-dll.ps1, pgo-build.ps1, pgo-build.sh: obsolete windows/PGO build helpers
- Remove .gitlab-ci.yml: entirely commented-out dead config

build-citron-linux.sh:
- Add ALSA + PulseAudio dev packages as required  across all supported package managers (apt, pacman, dnf, yum, zypper, emerge) to encourage Linux audio output to be present in packaged AppImages

AppImageBuilder/package-citron-linux.sh:
- Expand AppDir post-packaging cleanup: remove additional Qt plugin dirs, stale symlinks, and other bloat before the AppImage is assembled
This commit is contained in:
cheezwiz7899
2026-07-02 10:09:43 +10:00
parent 62542c8a50
commit ff2f3dc414
13 changed files with 64 additions and 1941 deletions
-435
View File
@@ -1,435 +0,0 @@
# GitLab CI config for Citron - DISABLED
# This CI configuration has been disabled as GitHub Actions is now being used
# To re-enable, uncomment the configuration below
# stages:
# - build
# - test
# - package
# variables:
# BUILD_TYPE: "Release"
# CMAKE_BUILD_PARALLEL_LEVEL: "4"
# DOCKER_DRIVER: overlay2
# DOCKER_TLS_CERTDIR: ""
# # Cache configuration for faster builds
# cache:
# paths:
# - build/vcpkg_installed/
# - build/_deps/
# key: "$CI_COMMIT_REF_SLUG"
# policy: pull-push
# # Linux Build (CachyOS optimized)
# build-linux:
# stage: build
# image: cachyos/cachyos:latest
# tags:
# - citron-build
# before_script:
# - pacman -Syu --noconfirm
# - pacman -S --noconfirm alsa-lib base-devel boost boost-libs catch2 cmake curl ffmpeg fmt fuse2 gamemode gcc gdb git glslang glu libusb libxi libxkbcommon libxkbcommon-x11 libxss libzip lz4 mbedtls2 mesa nasm ninja nlohmann-json openal openssl opus perl pipewire-audio pulseaudio pulseaudio-alsa qt6-base qt6-multimedia qt6-tools qt6-wayland sdl2 sdl2-compat unzip vulkan-headers vulkan-icd-loader vulkan-mesa-layers wget xcb-util-cursor xcb-util-image xcb-util-keysyms xcb-util-renderutil xcb-util-wm xorg-server-xvfb zip zstd zsync
# - echo '#!/bin/bash' > /usr/local/bin/shasum
# - echo 'if [ "$1" = "-a" ] && [ "$2" = "256" ]; then' >> /usr/local/bin/shasum
# - echo ' shift 2' >> /usr/local/bin/shasum
# - echo ' sha256sum "$@"' >> /usr/local/bin/shasum
# - echo 'else' >> /usr/local/bin/shasum
# - echo ' sha256sum "$@"' >> /usr/local/bin/shasum
# - echo 'fi' >> /usr/local/bin/shasum
# - chmod +x /usr/local/bin/shasum
# script: |
# # Clean and reset submodules to handle any inconsistencies
# git submodule deinit --all --force || true
# # Forcefully remove stale lock files that can block submodule updates
# find .git/modules -type f -name "*.lock" -delete
# git submodule update --init --recursive --force
# mkdir -p build && cd build
# # Dynamically find the Qt private header path
# 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")")
# echo "Found Qt private include directory: ${QT_PRIVATE_INCLUDE_DIR}"
# # Configure and build with the dynamically found path
# cmake .. \
# -G Ninja \
# -DCMAKE_C_COMPILER=gcc \
# -DCMAKE_CXX_COMPILER=g++ \
# -DCMAKE_BUILD_TYPE=Release \
# -DCMAKE_INSTALL_PREFIX=/usr \
# -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
# -DUSE_SYSTEM_QT=ON \
# -DCMAKE_C_FLAGS="-O3 -ffast-math -funsafe-math-optimizations -fno-math-errno -fno-trapping-math -freciprocal-math -ffp-contract=fast -fassociative-math -fno-rounding-math -fno-signaling-nans -march=x86-64-v2 -mtune=native -fomit-frame-pointer -fstrict-aliasing -frename-registers -fno-plt -funroll-loops -floop-interchange -floop-strip-mine -floop-block -fprefetch-loop-arrays -fpredictive-commoning -ftree-vectorize -fsplit-paths -finline-functions -finline-limit=1000 -finline-functions-called-once -fgcse-sm -fgcse-las -freorder-blocks-and-partition -fipa-pta -fipa-cp-clone -fwhole-program -flto=auto -fuse-linker-plugin -fvisibility=hidden -fdata-sections -ffunction-sections -fno-semantic-interposition -fopenmp -fexceptions -frtti" \
# -DCMAKE_CXX_FLAGS="-I${QT_PRIVATE_INCLUDE_DIR} -O3 -ffast-math -funsafe-math-optimizations -fno-math-errno -fno-trapping-math -freciprocal-math -ffp-contract=fast -fassociative-math -fno-rounding-math -fno-signaling-nans -march=x86-64-v2 -mtune=native -fomit-frame-pointer -fstrict-aliasing -frename-registers -fno-plt -funroll-loops -floop-interchange -floop-strip-mine -floop-block -fprefetch-loop-arrays -fpredictive-commoning -ftree-vectorize -fsplit-paths -finline-functions -finline-limit=1000 -finline-functions-called-once -fgcse-sm -fgcse-las -freorder-blocks-and-partition -fipa-pta -fipa-cp-clone -fwhole-program -flto=auto -fuse-linker-plugin -fvisibility=hidden -fdata-sections -ffunction-sections -fno-semantic-interposition -fopenmp -fexceptions -frtti -Wno-error -w" \
# -DCMAKE_EXE_LINKER_FLAGS="-Wl,--gc-sections -Wl,-O2 -Wl,--as-needed" \
# -DSDL_PIPEWIRE=OFF \
# -DCITRON_USE_BUNDLED_VCPKG=OFF \
# -DUSE_DISCORD_PRESENCE=OFF \
# -DBUNDLE_SPEEX=ON \
# -DCITRON_USE_BUNDLED_FFMPEG=OFF \
# -DCITRON_USE_QT_MULTIMEDIA=OFF \
# -DCITRON_USE_QT_WEB_ENGINE=OFF
# ninja
# cd ..
# echo "Build completed, checking for executables..."
# ls -la build/bin/ || echo "No build/bin directory found"
# find build/ -name "*.so" -o -name "citron*" | head -20 || echo "No shared libraries or executables found"
# echo "Checking library dependencies..."
# ldd build/bin/citron || echo "citron binary not found or ldd failed"
# chmod +x AppImage-build-local.sh
# echo "Attempting AppImage build with FUSE workaround..."
# export APPIMAGE_EXTRACT_AND_RUN=1
# export ARCH=x86_64
# export VERSION=$(git describe --tags --always)
# echo "Testing shasum compatibility..."
# which shasum || echo "shasum not found in PATH"
# echo "Testing shasum -a 256 syntax..."
# echo "test" | shasum -a 256 || echo "shasum -a 256 failed"
# echo "test" | sha256sum || echo "sha256sum failed"
# echo "Running AppImage build..."
# ./AppImage-build-local.sh || echo "AppImage build failed, continuing..."
# ls -la *.AppImage || echo "No AppImage files found"
# echo "AppImage size information:"
# du -h *.AppImage || echo "No AppImage to measure"
# echo "Total artifact size:"
# du -sh citron.AppImage build/bin/citron 2>/dev/null || echo "Cannot measure artifact sizes"
# echo "Compressing AppImage for upload..."
# gzip -9 -c citron.AppImage > citron.AppImage.gz
# ls -la citron.AppImage.gz
# du -h citron.AppImage.gz
# echo "AppImage compressed with gzip successfully"
# tar -czf citron-binary.tar.gz build/bin/
# ls -la citron-binary.tar.gz
# du -h citron-binary.tar.gz
# artifacts:
# paths:
# - citron.AppImage.gz
# - citron-binary.tar.gz
# expire_in: 1 week
# when: always
# only:
# - main
# - master
# - develop
# - ci-fixes
# - Boss-Build-Flags-For-CI-CMAKE-ON-CachyOS
# - merge_requests
# # Linux Build (CachyOS v3 optimized)
# build-linux-v3:
# stage: build
# image: cachyos/cachyos-v3
# tags:
# - citron-build
# before_script:
# - pacman -Syu --noconfirm
# - pacman -S --noconfirm alsa-lib base-devel boost boost-libs catch2 cmake curl ffmpeg fmt fuse2 gamemode gcc gdb git glslang glu libusb libxi libxkbcommon libxkbcommon-x11 libxss libzip lz4 mbedtls2 mesa nasm ninja nlohmann-json openal openssl opus perl pipewire-audio pulseaudio pulseaudio-alsa python-pip qt6-base qt6-multimedia qt6-tools qt6-wayland sdl2 sdl2-compat unzip vulkan-headers vulkan-icd-loader vulkan-mesa-layers wget xcb-util-cursor xcb-util-image xcb-util-keysyms xcb-util-renderutil xcb-util-wm xorg-server-xvfb zip zstd zsync
# - echo '#!/bin/bash' > /usr/local/bin/shasum
# - echo 'if [ "$1" = "-a" ] && [ "$2" = "256" ]; then' >> /usr/local/bin/shasum
# - echo ' shift 2' >> /usr/local/bin/shasum
# - echo ' sha256sum "$@"' >> /usr/local/bin/shasum
# - echo 'else' >> /usr/local/bin/shasum
# - echo ' sha256sum "$@"' >> /usr/local/bin/shasum
# - echo 'fi' >> /usr/local/bin/shasum
# - chmod +x /usr/local/bin/shasum
# script: |
# git submodule deinit --all --force || true
# find .git/modules -type f -name "*.lock" -delete
# git submodule update --init --recursive --force
# mkdir -p build && cd build
# 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")")
# echo "Found Qt private include directory: ${QT_PRIVATE_INCLUDE_DIR}"
# cmake .. \
# -G Ninja \
# -DCMAKE_C_COMPILER=gcc \
# -DCMAKE_CXX_COMPILER=g++ \
# -DCMAKE_BUILD_TYPE=Release \
# -DCMAKE_INSTALL_PREFIX=/usr \
# -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
# -DCMAKE_C_FLAGS="-O3 -ffast-math -funsafe-math-optimizations -fno-math-errno -fno-trapping-math -freciprocal-math -ffp-contract=fast -fassociative-math -fno-rounding-math -fno-signaling-nans -march=x86-64-v3 -mtune=native -fomit-frame-pointer -fstrict-aliasing -frename-registers -fno-plt -funroll-loops -floop-interchange -floop-strip-mine -floop-block -fprefetch-loop-arrays -fpredictive-commoning -ftree-vectorize -fsplit-paths -finline-functions -finline-limit=1000 -finline-functions-called-once -fgcse-sm -fgcse-las -freorder-blocks-and-partition -fipa-pta -fipa-cp-clone -fwhole-program -flto=auto -fuse-linker-plugin -fvisibility=hidden -fdata-sections -ffunction-sections -fno-semantic-interposition -fopenmp -fexceptions -frtti" \
# -DCMAKE_CXX_FLAGS="-I${QT_PRIVATE_INCLUDE_DIR} -O3 -ffast-math -funsafe-math-optimizations -fno-math-errno -fno-trapping-math -freciprocal-math -ffp-contract=fast -fassociative-math -fno-rounding-math -fno-signaling-nans -march=x86-64-v3 -mtune=native -fomit-frame-pointer -fstrict-aliasing -frename-registers -fno-plt -funroll-loops -floop-interchange -floop-strip-mine -floop-block -fprefetch-loop-arrays -fpredictive-commoning -ftree-vectorize -fsplit-paths -finline-functions -finline-limit=1000 -finline-functions-called-once -fgcse-sm -fgcse-las -freorder-blocks-and-partition -fipa-pta -fipa-cp-clone -fwhole-program -flto=auto -fuse-linker-plugin -fvisibility=hidden -fdata-sections -ffunction-sections -fno-semantic-interposition -fopenmp -fexceptions -frtti -Wno-error -w" \
# -DCMAKE_EXE_LINKER_FLAGS="-Wl,--gc-sections -Wl,-O2 -Wl,--as-needed" \
# -DSDL_PIPEWIRE=OFF \
# -DCITRON_USE_BUNDLED_VCPKG=OFF \
# -DUSE_DISCORD_PRESENCE=OFF \
# -DBUNDLE_SPEEX=ON \
# -DCITRON_USE_BUNDLED_FFMPEG=OFF \
# -DCITRON_USE_QT_MULTIMEDIA=OFF \
# -DCITRON_USE_QT_WEB_ENGINE=OFF
# ninja
# cd ..
# echo "Build completed, checking for executables..."
# ls -la build/bin/ || echo "No build/bin directory found"
# find build/ -name "*.so" -o -name "citron*" | head -20 || echo "No shared libraries or executables found"
# echo "Checking library dependencies..."
# ldd build/bin/citron || echo "citron binary not found or ldd failed"
# chmod +x AppImage-build-local.sh
# echo "Attempting AppImage build with FUSE workaround..."
# export APPIMAGE_EXTRACT_AND_RUN=1
# export ARCH=x86_64
# export VERSION=$(git describe --tags --always)
# echo "Testing shasum compatibility..."
# which shasum || echo "shasum not found in PATH"
# echo "Testing shasum -a 256 syntax..."
# echo "test" | shasum -a 256 || echo "shasum -a 256 failed"
# echo "test" | sha256sum || echo "sha256sum failed"
# echo "Running AppImage build..."
# ./AppImage-build-local.sh || echo "AppImage build failed, continuing..."
# ls -la *.AppImage || echo "No AppImage files found"
# echo "AppImage size information:"
# du -h *.AppImage || echo "No AppImage to measure"
# echo "Total artifact size:"
# du -sh citron.AppImage build/bin/citron 2>/dev/null || echo "Cannot measure artifact sizes"
# echo "Compressing AppImage for upload..."
# gzip -9 -c citron.AppImage > citron.AppImage.gz
# ls -la citron.AppImage.gz
# du -h citron.AppImage.gz
# echo "AppImage compressed with gzip successfully"
# tar -czf citron-binary.tar.gz build/bin/
# ls -la citron-binary.tar.gz
# du -h citron-binary.tar.gz
# artifacts:
# paths:
# - citron.AppImage.gz
# - citron-binary.tar.gz
# expire_in: 1 week
# when: always
# only:
# - main
# - master
# - develop
# - ci-fixes
# - Boss-Build-Flags-For-CI-CMAKE-ON-CachyOS
# - merge_requests
# # Linux Build (Steam Deck optimized - AMD Zen 2)
# build-linux-steamdeck:
# stage: build
# image: cachyos/cachyos:latest
# tags:
# - citron-build
# before_script:
# - pacman -Syu --noconfirm
# - pacman -S --noconfirm alsa-lib base-devel boost boost-libs catch2 cmake curl ffmpeg fmt fuse2 gamemode gcc gdb git glslang glu libusb libxi libxkbcommon libxkbcommon-x11 libxss libzip lz4 mbedtls2 mesa nasm ninja nlohmann-json openal openssl opus perl pipewire-audio pulseaudio pulseaudio-alsa python-pip qt6-base qt6-multimedia qt6-tools qt6-wayland sdl2 sdl2-compat unzip vulkan-headers vulkan-icd-loader vulkan-mesa-layers wget xcb-util-cursor xcb-util-image xcb-util-keysyms xcb-util-renderutil xcb-util-wm xorg-server-xvfb zip zstd zsync
# - echo '#!/bin/bash' > /usr/local/bin/shasum
# - echo 'if [ "$1" = "-a" ] && [ "$2" = "256" ]; then' >> /usr/local/bin/shasum
# - echo ' shift 2' >> /usr/local/bin/shasum
# - echo ' sha256sum "$@"' >> /usr/local/bin/shasum
# - echo 'else' >> /usr/local/bin/shasum
# - echo ' sha256sum "$@"' >> /usr/local/bin/shasum
# - echo 'fi' >> /usr/local/bin/shasum
# - chmod +x /usr/local/bin/shasum
# script: |
# git submodule deinit --all --force || true
# find .git/modules -type f -name "*.lock" -delete
# git submodule update --init --recursive --force
# mkdir -p build && cd build
# 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")")
# echo "Found Qt private include directory: ${QT_PRIVATE_INCLUDE_DIR}"
# cmake .. \
# -G Ninja \
# -DCMAKE_C_COMPILER=gcc \
# -DCMAKE_CXX_COMPILER=g++ \
# -DCMAKE_BUILD_TYPE=Release \
# -DCMAKE_INSTALL_PREFIX=/usr \
# -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
# -DCMAKE_C_FLAGS="-O3 -ffast-math -funsafe-math-optimizations -fno-math-errno -fno-trapping-math -freciprocal-math -ffp-contract=fast -fassociative-math -fno-rounding-math -fno-signaling-nans -march=znver2 -mtune=znver2 -fomit-frame-pointer -fstrict-aliasing -frename-registers -fno-plt -funroll-loops -floop-interchange -floop-strip-mine -floop-block -fprefetch-loop-arrays -fpredictive-commoning -ftree-vectorize -fsplit-paths -finline-functions -finline-limit=1000 -finline-functions-called-once -fgcse-sm -fgcse-las -freorder-blocks-and-partition -fipa-pta -fipa-cp-clone -fwhole-program -flto=auto -fuse-linker-plugin -fvisibility=hidden -fdata-sections -ffunction-sections -fno-semantic-interposition -fopenmp -fexceptions -frtti" \
# -DCMAKE_CXX_FLAGS="-I${QT_PRIVATE_INCLUDE_DIR} -O3 -ffast-math -funsafe-math-optimizations -fno-math-errno -fno-trapping-math -freciprocal-math -ffp-contract=fast -fassociative-math -fno-rounding-math -fno-signaling-nans -march=znver2 -mtune=znver2 -fomit-frame-pointer -fstrict-aliasing -frename-registers -fno-plt -funroll-loops -floop-interchange -floop-strip-mine -floop-block -fprefetch-loop-arrays -fpredictive-commoning -ftree-vectorize -fsplit-paths -finline-functions -finline-limit=1000 -finline-functions-called-once -fgcse-sm -fgcse-las -freorder-blocks-and-partition -fipa-pta -fipa-cp-clone -fwhole-program -flto=auto -fuse-linker-plugin -fvisibility=hidden -fdata-sections -ffunction-sections -fno-semantic-interposition -fopenmp -fexceptions -frtti -Wno-error -w" \
# -DCMAKE_EXE_LINKER_FLAGS="-Wl,--gc-sections -Wl,-O2 -Wl,--as-needed" \
# -DSDL_PIPEWIRE=OFF \
# -DCITRON_USE_BUNDLED_VCPKG=OFF \
# -DUSE_DISCORD_PRESENCE=OFF \
# -DBUNDLE_SPEEX=ON \
# -DCITRON_USE_BUNDLED_FFMPEG=OFF \
# -DCITRON_USE_QT_MULTIMEDIA=OFF \
# -DCITRON_USE_QT_WEB_ENGINE=OFF
# ninja
# cd ..
# echo "Build completed, checking for executables..."
# ls -la build/bin/ || echo "No build/bin directory found"
# find build/ -name "*.so" -o -name "citron*" | head -20 || echo "No shared libraries or executables found"
# echo "Checking library dependencies..."
# ldd build/bin/citron || echo "citron binary not found or ldd failed"
# chmod +x AppImage-build-local.sh
# echo "Attempting AppImage build with FUSE workaround..."
# export APPIMAGE_EXTRACT_AND_RUN=1
# export ARCH=x86_64
# export VERSION=$(git describe --tags --always)
# echo "Testing shasum compatibility..."
# which shasum || echo "shasum not found in PATH"
# echo "Testing shasum -a 256 syntax..."
# echo "test" | shasum -a 256 || echo "shasum -a 256 failed"
# echo "test" | sha256sum || echo "sha256sum failed"
# echo "Running AppImage build..."
# ./AppImage-build-local.sh || echo "AppImage build failed, continuing..."
# ls -la *.AppImage || echo "No AppImage files found"
# echo "AppImage size information:"
# du -h *.AppImage || echo "No AppImage to measure"
# echo "Total artifact size:"
# du -sh citron.AppImage build/bin/citron 2>/dev/null || echo "Cannot measure artifact sizes"
# echo "Compressing AppImage for upload..."
# gzip -9 -c citron.AppImage > citron.AppImage.gz
# ls -la citron.AppImage.gz
# du -h citron.AppImage.gz
# echo "AppImage compressed with gzip successfully"
# tar -czf citron-binary.tar.gz build/bin/
# ls -la citron-binary.tar.gz
# du -h citron-binary.tar.gz
# artifacts:
# paths:
# - citron.AppImage.gz
# - citron-binary.tar.gz
# expire_in: 1 week
# when: always
# only:
# - main
# - master
# - develop
# - ci-fixes
# - Boss-Build-Flags-For-CI-CMAKE-ON-CachyOS
# - merge_requests
# # Android Build (Ubuntu 24.04 optimized)
# build-android:
# stage: build
# image: ubuntu:24.04
# tags:
# - citron-build
# before_script:
# - apt-get update -qq
# - apt-get install -y -qq openjdk-17-jdk wget unzip curl git cmake build-essential pkg-config zip glslang-tools
# - 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
# - export ANDROID_SDK_ROOT=$PWD/android-sdk
# - export PATH=$PATH:$ANDROID_SDK_ROOT/cmdline-tools/latest/bin
# - printf "y\ny\ny\ny\ny\ny\ny\n" | sdkmanager --licenses || true
# - sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0"
# - wget -q https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
# - unzip -q android-ndk-r26b-linux.zip
# - export ANDROID_NDK_HOME=$PWD/android-ndk-r26b
# script:
# - git submodule deinit --all --force || true
# - git submodule update --init --recursive --force
# - cmake -B build-android -S . -DCMAKE_BUILD_TYPE=$BUILD_TYPE -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
# - cmake --build build-android --config $BUILD_TYPE --parallel $CMAKE_BUILD_PARALLEL_LEVEL
# - cd src/android
# - ./gradlew assembleMainlineRelease
# artifacts:
# paths:
# - src/android/app/build/outputs/apk/mainline/release/*.apk
# expire_in: 1 week
# only:
# - main
# - master
# - develop
# - ci-fixes
# - merge_requests
# allow_failure: true
# # Unit Tests
# test-unit:
# stage: test
# image: ubuntu:24.04
# tags:
# - citron-build
# before_script:
# # Set the environment to be non-interactive
# - export DEBIAN_FRONTEND=noninteractive
#
# # Update package lists and install tool for managing repositories
# - apt-get update -qq
# - apt-get install -y -qq software-properties-common
#
# # Reliably add the 'universe' and 'multiverse' repositories
# - add-apt-repository universe
# - add-apt-repository multiverse
#
# # Update the package lists again to include the new repositories
# - apt-get update -qq
#
# # Install all required system packages for the build
# - apt-get install -y -qq
# build-essential
# cmake
# ninja-build
# git
# pkg-config
# catch2
# libasound2-dev
# libpulse-dev
# libboost-all-dev
# libavcodec-dev
# libavfilter-dev
# libavformat-dev
# libavutil-dev
# libswscale-dev
# llvm-17-dev
# gamemode-dev
# libenet-dev
# libfmt-dev
# liblz4-dev
# libopus-dev
# libssl-dev
# libusb-1.0-0-dev
# libvulkan-dev
# nlohmann-json3-dev
# zlib1g-dev
# libzstd-dev
# libopenal-dev
# libedit-dev
# libcurl4-openssl-dev
# libstb-dev
# libcubeb-dev
# libspeexdsp-dev
# libva-dev
# glslang-tools
# libx11-dev
#
# script:
# - git submodule deinit --all --force || true
# - git submodule update --init --recursive --force
# - cmake -B build-test -S . -DCMAKE_BUILD_TYPE=Debug -DCITRON_TESTS=ON -DENABLE_QT=OFF -DENABLE_SDL2=OFF -DENABLE_WEB_SERVICE=OFF
# - cmake --build build-test --config Debug --parallel $CMAKE_BUILD_PARALLEL_LEVEL
# - cd build-test
# - ctest --output-on-failure
# artifacts:
# reports:
# junit: build-test/Testing/**/*.xml
# expire_in: 1 week
# only:
# - main
# - master
# - develop
# - ci-fixes
# - merge_requests
# # Package Release
# package-release:
# stage: package
# image: ubuntu:24.04
# tags:
# - citron-build
# dependencies:
# - build-linux
# script:
# - mkdir -p release
# - echo "Creating release package..."
# - tar -czf citron-release-$(date +%Y%m%d).tar.gz release/ || true
# artifacts:
# paths:
# - citron-release-*.tar.gz
# expire_in: 1 month
# only:
# - main
# - master
# - develop
# - ci-fixes
# - tags
-83
View File
@@ -1,83 +0,0 @@
#! /bin/bash
set -e
# Make sure script is called from inside our container
test -e /tmp/torzu-src-ro || (echo "Script MUST NOT be called directly!" ; exit 1)
# Set up environment
export LANG=C.UTF-8
export LC_ALL=C.UTF-8
unset LC_ADDRESS LC_NAME LC_MONETARY LC_PAPER LC_TELEPHONE LC_MEASUREMENT LC_TIME
# Raise max open files count
ulimit -n 50000
# Install dependencies
apt -y install cmake ninja-build build-essential autoconf pkg-config locales wget git file mold libtool lsb-release wget software-properties-common gnupg \
qtbase5-dev qtmultimedia5-dev qtbase5-private-dev glslang-tools libssl-dev libavcodec-dev libavfilter-dev libavutil-dev libswscale-dev libpulse-dev libasound2-dev
if [ ! "$BUILD_USE_CPM" = 1 ]; then
apt -y install libfmt-dev libenet-dev liblz4-dev nlohmann-json3-dev zlib1g-dev libopus-dev libsimpleini-dev libstb-dev libzstd-dev libusb-1.0-0-dev libcubeb-dev libcpp-jwt-dev libvulkan-dev gamemode-dev libasound2-dev libglu1-mesa-dev libxext-dev mesa-common-dev libva-dev
if [ ! -f /usr/local/lib/cmake/Boost-1.88.0/BoostConfigVersion.cmake ]; then
# Install Boost
wget https://archives.boost.io/release/1.88.0/source/boost_1_88_0.tar.bz2
echo "Extracting Boost sources..."
tar xf boost_1_88_0.tar.bz2
cd boost_1_88_0
./bootstrap.sh
./b2 install --with-{headers,context,system,fiber,atomic,filesystem} link=static
cd ..
rm -rf boost_1_88_0 boost_1_88_0.tar.bz2
fi
fi
# Install Clang
if ([ "$BUILD_USE_CLANG" = 1 ] && ! clang-19 --version); then
cd /tmp
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
./llvm.sh 19
rm llvm.sh
fi
# Mount Torzu sources with temporary overlay
cd /tmp
mkdir torzu-src-upper torzu-src-work torzu-src
mount -t overlay overlay -olowerdir=torzu-src-ro,upperdir=torzu-src-upper,workdir=torzu-src-work torzu-src
# Get extra configuration/compilation options
EXTRA_COMPILE_FLAGS=""
EXTRA_CMAKE_FLAGS=""
if [ "$BUILD_USE_CLANG" = 1 ]; then
EXTRA_CMAKE_FLAGS="-DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19"
FATLTO_FLAG="-flto=full"
else
FATLTO_FLAG="-flto"
fi
if [ "$BUILD_USE_THIN_LTO" = 1 ]; then
EXTRA_COMPILE_FLAGS="-flto=thin"
fi
if [ "$BUILD_USE_FAT_LTO" = 1 ]; then
EXTRA_COMPILE_FLAGS="$FATLTO_FLAG"
fi
if [ "$BUILD_USE_CPM" = 1 ]; then
EXTRA_CMAKE_FLAGS="$EXTRA_CMAKE_FLAGS -DYUZU_USE_CPM=ON"
fi
# Build Torzu
cd /tmp
mkdir torzu-build
cd torzu-build
cmake /tmp/torzu-src -GNinja -DCMAKE_BUILD_TYPE=Release -DYUZU_TESTS=OFF -DENABLE_QT_TRANSLATION=OFF -DSPIRV_WERROR=OFF -DCMAKE_FIND_LIBRARY_SUFFIXES=".a;.so" -DSPIRV-Headers_SOURCE_DIR=/tmp/torzu-src/externals/SPIRV-Headers -DCMAKE_{C,CXX}_FLAGS="$EXTRA_COMPILE_FLAGS -fdata-sections -ffunction-sections" -DCMAKE_{EXE,SHARED}_LINKER_FLAGS="-Wl,--gc-sections" $EXTRA_CMAKE_FLAGS
ninja || (
echo "Compilation has failed. Dropping you into a shell so you can inspect the situation. Run 'ninja' to retry and exit shell once compilation has finished successfully."
echo "Note that any changes made here will not be reflected to the host environment, but changes made from the host environment will be reflected here."
bash
)
# Generate AppImage
cp -rv /tmp/torzu-src/AppImageBuilder /tmp/AppImageBuilder
cd /tmp/AppImageBuilder
./build.sh /tmp/torzu-build /tmp/torzu.AppImage || echo "This error is known. Using workaround..."
cp /lib/$(uname -m)-linux-gnu/libICE.so.6 build/
mv build /tmp/hosttmp/torzu-debian-appimage-rootfs
-73
View File
@@ -1,73 +0,0 @@
#! /bin/bash
set -e
# Parse options
for i in "$@"
do
case $i in
-l|--clang)
export BUILD_USE_CLANG=1
echo "-> Using Clang for compilation."
;;
-o|--thin-lto)
export BUILD_USE_THIN_LTO=1
echo "-> Thin link time optimization enabled."
;;
-O|--fat-lto)
export BUILD_USE_FAT_LTO=1
echo "-> Fat link time optimization enabled."
;;
-p|--use-cpm)
export BUILD_USE_CPM=1
echo "-> Using CPM to download most dependencies."
;;
-k|--keep-rootfs)
BUILD_KEEP_ROOTFS=1
echo "-> Not deleting rootfs after successful build."
;;
*)
echo "Usage: $0 [--clang/-l] [--thin-lto/-o] [--fat-lto/-O] [--use-cpm/-p] [--keep-rootfs/-k]"
exit 1
;;
esac
done
# Make sure options are valid
if [ "$BUILD_USE_THIN_LTO" = 1 ] && [ "$BUILD_USE_CLANG" != 1 ]; then
echo "Thin LTO can't be used without Clang!"
exit 2
fi
if [ "$BUILD_USE_THIN_LTO" = 1 ] && [ "$BUILD_USE_FAT_LTO" = 1 ]; then
echo "Only either thin or fat LTO can be used!"
exit 2
fi
# Get citron source dir
citron_SOURCE_DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
echo "-> Source dir is $citron_SOURCE_DIR"
rm -rf "$citron_SOURCE_DIR/AppImageBuilder/build"
# Generate debian rootfs
cd /tmp
echo "Cleaning up before build..."
rm -rf citron-debian-appimage-rootfs
[ -d rootfs-citron-appimage-build ] ||
debootstrap stable rootfs-citron-appimage-build http://deb.debian.org/debian/
bwrap --bind rootfs-citron-appimage-build / \
--unshare-pid \
--dev-bind /dev /dev --proc /proc --tmpfs /tmp --ro-bind /sys /sys --dev-bind /run /run \
--tmpfs /var/tmp \
--chmod 1777 /tmp \
--ro-bind /etc/resolv.conf /etc/resolv.conf \
--ro-bind "$citron_SOURCE_DIR" /tmp/citron-src-ro \
--chdir / \
--tmpfs /home \
--setenv HOME /home \
--bind /tmp /tmp/hosttmp \
/tmp/citron-src-ro/AppImage-build-debian-inner.sh
appimagetool citron-debian-appimage-rootfs citron.AppImage
echo "AppImage generated at /tmp/citron.AppImage! Cleaning up..."
rm -rf citron-debian-appimage-rootfs
if [ ! "$BUILD_KEEP_ROOTFS" = 1 ]; then
rm -rf rootfs-citron-appimage-build
fi
-42
View File
@@ -1,42 +0,0 @@
#!/bin/bash
FILE=build/bin/citron
if test -f "$FILE"; then
# remove any previously made AppImage in the base citron git folder
rm ./citron.AppImage
# enter AppImage utility folder
cd AppImageBuilder
# run the build script to create the AppImage
# (usage) ./build.sh [source citron build folder] [destination .AppImage file]
./build.sh ../build ./citron.AppImage
FILE=./citron.AppImage
if test -f "$FILE"; then
# move the AppImage to the main citron folder
mv citron.AppImage ..
# return to main citron folder
cd ..
# show contents of current folder
echo
ls
# show AppImages specifically
echo
ls *.AppImage
echo
echo "'citron.AppImage' is now located in the current folder."
echo
else
cd ..
echo "AppImage was not built."
fi
else
echo
echo "$FILE does not exist."
echo
echo "No citron executable found in the /citron/build/bin folder!"
echo
echo "You must first build a native linux version of citron before running this script!"
echo
fi
-104
View File
@@ -1,104 +0,0 @@
#!/bin/bash
set -e
# Get script directory
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
BUILD_DIR_RAW="${1:-$SCRIPT_DIR/../build/generate}"
BUILD_DIR="$(readlink -f "${BUILD_DIR_RAW}")"
# Save environment overrides
ENV_QT_PATH="${CITRON_QT_PATH:-}"
ENV_ICU_PATH="${CITRON_ICU_PATH:-}"
ENV_XCB_PATH="${CITRON_XCB_PATH:-}"
ENV_BINARY_DIR="${CITRON_BINARY_DIR:-}"
if [ ! -f "$BUILD_DIR/AppImageBuilder/config.sh" ]; then
echo "Error: config.sh not found in $BUILD_DIR/AppImageBuilder/"
echo "Please run CMake first."
exit 1
fi
source "$BUILD_DIR/AppImageBuilder/config.sh"
# Allow environment variables to override config.sh
export CITRON_QT_PATH="${ENV_QT_PATH:-$CITRON_QT_PATH}"
export CITRON_ICU_PATH="${ENV_ICU_PATH:-$CITRON_ICU_PATH}"
export CITRON_XCB_PATH="${ENV_XCB_PATH:-$CITRON_XCB_PATH}"
export CITRON_BINARY_DIR="${ENV_BINARY_DIR:-$CITRON_BINARY_DIR}"
# Tools setup
TOOLS_DIR="$BUILD_DIR/AppImageBuilder/tools"
mkdir -p "$TOOLS_DIR"
LINUXDEPLOY="$TOOLS_DIR/linuxdeploy-x86_64.AppImage"
LINUXDEPLOY_QT="$TOOLS_DIR/linuxdeploy-plugin-qt-x86_64.AppImage"
download_tool() {
local url=$1
local file=$2
if [ ! -f "$file" ]; then
echo "Downloading $file..."
wget -q --show-progress "$url" -O "$file"
chmod +x "$file"
fi
}
download_tool "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage" "$LINUXDEPLOY"
download_tool "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage" "$LINUXDEPLOY_QT"
# AppDir setup
APPDIR="$BUILD_DIR/AppImageBuilder/AppDir"
rm -rf "$APPDIR"
mkdir -p "$APPDIR"
# Build the AppImage
# We need to tell linuxdeploy where our custom libraries are
export LD_LIBRARY_PATH="$CITRON_ICU_PATH:$CITRON_XCB_PATH/lib:$LD_LIBRARY_PATH"
export EXTRA_QT_PLUGINS="wayland" # Add any extra plugins needed
export NO_STRIP=1 # Avoid strip failures on modern binaries (SHT_RELR)
# Run linuxdeploy
# --plugin qt handles Qt dependencies
export QMAKE="$CITRON_QT_PATH/bin/qmake"
export QT_ROOT="$CITRON_QT_PATH"
export LD_LIBRARY_PATH="$CITRON_QT_PATH/lib:$CITRON_ICU_PATH:$CITRON_XCB_PATH/lib:${LD_LIBRARY_PATH:-}"
pushd "$BUILD_DIR" > /dev/null
# Run linuxdeploy to populate AppDir
"$LINUXDEPLOY" --appdir "$APPDIR" \
--executable "$CITRON_BINARY_DIR/citron" \
--desktop-file "$SCRIPT_DIR/assets/citron.desktop" \
--icon-file "$SCRIPT_DIR/assets/citron.svg" \
--library "$CITRON_ICU_PATH/libicuuc.so.73" \
--library "$CITRON_ICU_PATH/libicui18n.so.73" \
--library "$CITRON_ICU_PATH/libicudata.so.73" \
--library "$CITRON_XCB_PATH/lib/libxcb.so.1" \
--library "$CITRON_XCB_PATH/lib/libxcb-cursor.so.0" \
--library "$CITRON_XCB_PATH/lib/libxcb-xkb.so.1" \
--library "$CITRON_XCB_PATH/lib/libxcb-render.so.0" \
--library "$CITRON_XCB_PATH/lib/libxcb-render-util.so.0" \
--library "$CITRON_XCB_PATH/lib/libxcb-shape.so.0" \
--library "$CITRON_XCB_PATH/lib/libxcb-shm.so.0" \
--library "$CITRON_XCB_PATH/lib/libxcb-sync.so.1" \
--library "$CITRON_XCB_PATH/lib/libxcb-xfixes.so.0" \
--library "$CITRON_XCB_PATH/lib/libxcb-randr.so.0" \
--library "$CITRON_XCB_PATH/lib/libxcb-image.so.0" \
--library "$CITRON_XCB_PATH/lib/libxcb-keysyms.so.1" \
--library "$CITRON_XCB_PATH/lib/libxcb-icccm.so.4" \
--library "$CITRON_XCB_PATH/lib/libXau.so.6" \
--library "$CITRON_XCB_PATH/lib/libXdmcp.so.6" \
--plugin qt
# Inject the wrapper script to support portable mode (user folder) and PGO profiles
# We rename the real binary to citron.bin and put the script as 'citron'
if [ -f "$APPDIR/usr/bin/citron" ]; then
mv "$APPDIR/usr/bin/citron" "$APPDIR/usr/bin/citron.bin"
cp "$SCRIPT_DIR/assets/citron.sh" "$APPDIR/usr/bin/citron"
chmod +x "$APPDIR/usr/bin/citron"
fi
# Build the final AppImage
"$LINUXDEPLOY" --appdir "$APPDIR" --output appimage
popd > /dev/null
echo "AppImage build complete in $BUILD_DIR"
-170
View File
@@ -1,170 +0,0 @@
#! /bin/bash
set -e
# Check arguments
if [[ $# != 2 ]]; then
>&2 echo "Bad usage!"
echo "Usage: $0 <build dir> <output file>"
exit 1
fi
# Get paths
ARCH="$(uname -m)"
SYSTEM_LIBS="/usr/lib"
SYSTEM_LIBS64="/usr/lib64"
citron_BIN="${1}/bin"
citron_BIN_GUI="${citron_BIN}/citron"
# Make sure executable exists
if [[ $(file -b --mime-type "$citron_BIN_GUI") != application/x-pie-executable ]]; then
>&2 echo "Invalid citron executable!"
fi
# Clean up build dir
rm -rf build
mkdir build
# NOTE: some of these aren't used now, but can be reordered in priority when citron is converted to QT6
# QT5 - /usr/lib/${ARCH}-linux-gnu/qt5 (debian), /usr/lib64/qt5 (fedora), /usr/lib/qt (steam deck)
# QT5 - /usr/lib/${ARCH}-linux-gnu/qt6 (debian), /usr/lib64/qt6 (fedora), /usr/lib/qt6 (steam deck)
QTFOUND="true"
QTDIR="$SYSTEM_LIBS"/${ARCH}-linux-gnu/qt5/plugins
if [ ! -d "$QTDIR" ]; then
# default qt5 folder not found, check for 64-bit qt5 folder
QTDIR="$SYSTEM_LIBS64"/qt5/plugins
if [ ! -d "$QTDIR" ]; then
# 64-bit qt5 folder not found, check for Steam Deck qt (qt5) folder
QTDIR="$SYSTEM_LIBS"/qt/plugins
if [ ! -d "$QTDIR" ]; then
# Steam Deck qt (qt5) folder not found, check for regular qt6 folder
QTDIR="$SYSTEM_LIBS"/${ARCH}-linux-gnu/qt6/plugins
if [ ! -d "$QTDIR" ]; then
# regular qt6 folder not found, check for 64-bit qt6 folder
QTDIR="$SYSTEM_LIBS64"/qt6/plugins
if [ ! -d "$QTDIR" ]; then
# 64-bit qt6 folder not found, check for Steam Deck qt6 folder
QTDIR="$SYSTEM_LIBS"/qt6/plugins
if [ ! -d "$QTDIR" ]; then
QTFOUND="false"
fi
fi
fi
fi
fi
fi
if [ $QTFOUND == "true" ]; then
echo "QT plugins from $QTDIR will be used."
# Copy system dependencies used to build and required by the citron binary
# includes:
# - '/lib64/ld-linux-x86-64.so.2' or `/lib/ld-linux-aarch64.so.1` file per architecture
# - required files from `/usr/lib/x86_64-linux-gnu` or `/usr/lib/aarch64-linux-gnu`
# - different for SteamDeck, but still does it automatically
function copy_libs {
for lib in $(ldd "$1"); do
(cp -vn "$lib" ./build/ 2> /dev/null) || true
done
}
echo "Copying main dependencies..."
copy_libs "$citron_BIN_GUI"
# Copy QT dependency folders, path determined above
echo "Copying Qt dependencies..."
mkdir ./build/qt5
cp -rv "$QTDIR"/{imageformats,platforms,platformthemes,xcbglintegrations} ./build/qt5/
# Discover indirect dependencies (mostly from runtime-loaded Qt plugins)
echo "Copying extra dependencies..."
while true; do
LIBS="$(find ./build -name \*.so\*)"
LIB_COUNT=$(echo "$LIBS" | wc -l)
echo "$LIB_COUNT dependency libraries discovered so far..."
if [ $LIB_COUNT == "$PREV_LIB_COUNT" ]; then
break
fi
PREV_LIB_COUNT=$LIB_COUNT
for plib in $LIBS; do
if [ -f "$plib" ]; then
copy_libs "$plib"
fi
done
done
# Copy executable
cp -v "$citron_BIN_GUI" ./build/
# Copy assets for the appropriate arch
cp -v ./assets_"${ARCH}"/* ./build/
# Copy common assets
cp -v ./assets/* ./build/
# Strip all libraries and executables
for file in $(find ./build -type f); do
(strip -v "$file" 2> /dev/null) || true
done
PASSED_CHECKSUM="false"
FILE=appimagetool.AppImage
# total number of times to try downloading if a checksum doesn't match
DL_TRIES=3
while [ $PASSED_CHECKSUM == "false" ] && [ "$DL_TRIES" -gt 0 ]; do
case $ARCH in
x86_64)
# Static copy from the 'ext-linux-bin' repo.
# Checksum will need to be changed when/if this file in the repo is updated.
if ! test -f "$FILE"; then
echo "Downloading appimagetool for architecture '$ARCH'"
wget -O appimagetool.AppImage https://github.com/litucks/ext-linux-bin/raw/refs/heads/main/appimage/appimagetool-x86_64.AppImage
fi
if [ $(shasum -a 256 appimagetool.AppImage | cut -d' ' -f1) = "110751478abece165a18460acbd7fd1398701f74a9405ad8ac053427d937bd5d" ] ; then
PASSED_CHECKSUM="true"
fi
# DISABLED TO USE THE ABOVE
# The current continuous release channel option, until a static copy is put in 'ext-linux-bin'.
# The checksum will pass until the continuous release is updated, then a new one needs to be
# generated to update this script.
#if ! test -f "$FILE"; then
# echo "Downloading appimagetool for architecture '$ARCH'"
# wget -O appimagetool.AppImage https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
#fi
#if [ $(shasum -a 256 appimagetool.AppImage | cut -d' ' -f1) = "46fdd785094c7f6e545b61afcfb0f3d98d8eab243f644b4b17698c01d06083d1" ] ; then
# PASSED_CHECKSUM="true"
#fi
;;
aarch64)
# Currently set to the continuous release channel until a static copy is put in 'ext-linux-bin'.
# The checksum will pass until the continuous release is updated, then a new one needs to be
# generated to update this script.
if ! test -f "$FILE"; then
echo "Downloading appimagetool for architecture '$ARCH'"
wget -O appimagetool.AppImage https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-aarch64.AppImage
fi
if [ $(shasum -a 256 appimagetool.AppImage | cut -d' ' -f1) = "04f45ea45b5aa07bb2b071aed9dbf7a5185d3953b11b47358c1311f11ea94a96" ] ; then
PASSED_CHECKSUM="true"
fi
;;
*)
PASSED_CHECKSUM="invalid_arch"
;;
esac
# delete the appimagetool downloaded if the checksum doesn't match.
if [ ! $PASSED_CHECKSUM == "true" ]; then
rm -f appimagetool.AppImage
fi
((DL_TRIES-=1))
done
if [ $PASSED_CHECKSUM == "true" ]; then
echo "Checksum passed. Proceeding to build image."
# Build AppImage
chmod a+x appimagetool.AppImage
./appimagetool.AppImage ./build "$2"
elif [ $PASSED_CHECKSUM == "invalid_arch" ]; then
echo "No download found for architecture '$ARCH'. Building halted."
else
echo "Checksum for appimagetool does not match. Building halted."
echo "If the file to be downloaded has been changed, a new checksum will need to be generated for this script."
fi
else
echo "QT not found, aborting AppImage build."
fi
+19 -1
View File
@@ -373,7 +373,10 @@ mv -v ./*.AppImage.* "${OUTPATH}/" 2>/dev/null || true
# squashed into the AppImage above (every DEPLOY_*/STRACE_MODE suppression and
# the post-dep-scan find/-delete block above already ran before
# --make-appimage), so this is a complete, AppRun-runnable, install-free
# alternative to the AppImage.
# alternative to the AppImage — not a partial copy. (AppDir/usr/ is not used
# by this layout — translations land under AppDir/lib/qt6/, see comment above —
# so packing only "usr", as the pre-quick-sharun pipeline did, would produce a
# near-empty archive here.)
#
# AppDir is then removed. It has no further purpose once packed, and leaving
# it sitting in OUTPATH means anything that uploads/copies OUTPATH wholesale
@@ -384,4 +387,19 @@ if [ -d ./AppDir ]; then
rm -rf ./AppDir
fi
# Clean up build-tool byproducts that land in this same directory (OUTPATH),
# not just AppDir. build-citron-linux.sh sets OUTPATH to the same working
# directory this script cd's into and downloads tooling into, so anything
# these tools write to cwd ends up sitting next to the final artifacts unless
# removed explicitly:
#
# quick-sharun — the tool itself, copied to ./quick-sharun near the top of
# this script (see the vendoring comment above). It has no
# purpose after packaging finishes.
# appinfo — a debug/metadata text file written to cwd by the
# underlying appimagetool binary during --make-appimage.
# Not generated by quick-sharun.sh itself, not meant for
# redistribution — internal build debug output only.
rm -f ./quick-sharun ./appinfo
echo "Artifacts in: ${OUTPATH}"
Regular → Executable
+45
View File
@@ -447,6 +447,31 @@ _setup_apt() {
sudo apt-get install -y libvdpau-dev \
|| warn "libvdpau-dev unavailable — FFmpeg will build with --disable-vdpau"
# ── Linux audio output (ALSA + PulseAudio) — REQUIRED, not optional ─────
# SDL2's CheckALSA()/CheckPulseAudio() configure-time checks look for
# alsa/asoundlib.h and pulse/pulseaudio.h. If either header is missing,
# SDL2 silently disables that backend (SDL_ALSA / SDL_PULSEAUDIO → OFF)
# rather than hard-failing the build — the same "quiet fallback" pattern
# as the VAAPI/VDPAU checks above, except here the fallback is SDL2's
# SDL_DUMMYAUDIO/SDL_DISKAUDIO drivers, neither of which produces any
# actual sound. A machine missing both dev packages therefore still
# builds and packages successfully, but ships an AppImage with no
# functioning Linux audio output at all — a failure mode with no build
# warning to catch it, which is why this group is REQUIRED (unlike the
# --ignore-missing X11/XCB extras below).
#
# This also solves packaging determinism: package-citron-linux.sh finds
# libasound.so.2 and libpulse.so.0 to bundle into the AppImage via
# `ldconfig -p` against whatever happens to be installed on the machine
# running the packaging step (see comments there). Installing the -dev
# packages here pulls in their runtime libs (libasound2, libpulse0) as
# apt dependencies, so that probe now succeeds identically on every
# machine that runs this script — CI included — instead of depending on
# whether that machine happens to already have a desktop audio stack.
info "Installing ALSA + PulseAudio dev packages (required for audio output)..."
sudo apt-get install -y libasound2-dev libpulse-dev \
|| error "ALSA/PulseAudio dev packages failed to install — Linux builds would have no audio output"
# ── X11 / XCB optional extras (SDL2 Xi/XSS/XCB, Qt XCB platform plugin) ─
# These extend the X11 install above with input, screensaver, and XCB
# extension headers. All are optional — their cmake checks produce soft
@@ -496,6 +521,10 @@ _setup_pacman() {
# Optional: bundled into the AppImage by package-citron-linux.sh if present.
sudo pacman -S --needed --noconfirm gamemode 2>/dev/null || true
# ── Linux audio output (ALSA + PulseAudio) —
sudo pacman -S --needed --noconfirm alsa-lib libpulse \
|| error "ALSA/PulseAudio packages failed to install — Linux builds would have no audio output"
# Arch ships unversioned tools — symlink to versioned names
for tool in clang clang++ lld llvm-profdata llvm-bolt merge-fdata; do
local versioned="/usr/local/bin/${tool}-${CLANG_VERSION}"
@@ -538,6 +567,10 @@ _setup_dnf() {
# Optional: bundled into the AppImage by package-citron-linux.sh if present.
sudo dnf install -y gamemode 2>/dev/null || true
# ── Linux audio output (ALSA + PulseAudio) —
sudo dnf install -y alsa-lib-devel pulseaudio-libs-devel \
|| error "ALSA/PulseAudio dev packages failed to install — Linux builds would have no audio output"
}
_setup_yum() {
@@ -556,6 +589,10 @@ _setup_yum() {
# Optional: bundled into the AppImage by package-citron-linux.sh if present.
# May require EPEL or an RPM Fusion-style repo on RHEL-based distros.
sudo yum install -y gamemode 2>/dev/null || true
# ── Linux audio output (ALSA + PulseAudio) —
sudo yum install -y alsa-lib-devel pulseaudio-libs-devel \
|| error "ALSA/PulseAudio dev packages failed to install — Linux builds would have no audio output"
}
_setup_zypper() {
@@ -578,6 +615,10 @@ _setup_zypper() {
# Optional: bundled into the AppImage by package-citron-linux.sh if present.
sudo zypper install -y --no-recommends gamemode 2>/dev/null || true
# ── Linux audio output (ALSA + PulseAudio) —
sudo zypper install -y --no-recommends alsa-devel libpulse-devel \
|| error "ALSA/PulseAudio dev packages failed to install — Linux builds would have no audio output"
}
_setup_emerge() {
@@ -594,6 +635,10 @@ _setup_emerge() {
# Optional: bundled into the AppImage by package-citron-linux.sh if present.
sudo emerge --ask=n games-util/gamemode 2>/dev/null || true
# ── Linux audio output (ALSA + PulseAudio) —
sudo emerge --ask=n media-libs/alsa-lib media-libs/libpulse \
|| error "ALSA/PulseAudio packages failed to install — Linux builds would have no audio output"
}
_install_llvm_clang() {
-86
View File
@@ -1,86 +0,0 @@
@echo off
REM SPDX-FileCopyrightText: 2026 citron Emulator Project
REM SPDX-License-Identifier: GPL-3.0-or-later
REM
REM One-click MinGW build launcher for Citron Neo.
REM Finds your MSYS2 installation and runs build-for-mingw.sh in UCRT64 mode.
setlocal enabledelayedexpansion
REM ---------- locate MSYS2 ----------
set "MSYS2_PATH="
REM Check common install locations
for %%P in (
"C:\msys64"
"C:\msys2"
"%USERPROFILE%\msys64"
"%USERPROFILE%\msys2"
"D:\msys64"
"D:\msys2"
) do (
if exist "%%~P\usr\bin\bash.exe" (
set "MSYS2_PATH=%%~P"
goto :found_msys2
)
)
REM Try the PATH
where bash.exe >nul 2>&1
if %ERRORLEVEL% equ 0 (
for /f "delims=" %%I in ('where bash.exe') do (
set "BASH_LOC=%%~dpI"
if exist "!BASH_LOC!..\..\..\usr\bin\bash.exe" (
for %%J in ("!BASH_LOC!..\..\..") do set "MSYS2_PATH=%%~fJ"
goto :found_msys2
)
)
)
echo.
echo ERROR: Could not find an MSYS2 installation.
echo.
echo Please install MSYS2 from https://www.msys2.org/ and try again,
echo or set MSYS2_PATH before running this script:
echo.
echo set MSYS2_PATH=C:\msys64
echo build-for-mingw.bat
echo.
pause
exit /b 1
:found_msys2
echo Found MSYS2 at: %MSYS2_PATH%
REM ---------- resolve script path ----------
set "SCRIPT_DIR=%~dp0"
REM Remove trailing backslash
if "%SCRIPT_DIR:~-1%"=="\" set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
REM Convert Windows path to MSYS2 path (C:\foo\bar -> /c/foo/bar)
set "MSYS_SOURCE=%SCRIPT_DIR:\=/%"
set "MSYS_SOURCE=/%MSYS_SOURCE:~0,1%%MSYS_SOURCE:~2%"
REM Lowercase the drive letter
for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
set "MSYS_SOURCE=!MSYS_SOURCE:/%%a/=/%%a/!"
)
REM ---------- run the build ----------
echo.
echo Launching MSYS2 UCRT64 build ...
echo.
"%MSYS2_PATH%\usr\bin\env.exe" MSYSTEM=UCRT64 ^
"%MSYS2_PATH%\usr\bin\bash.exe" -lc ^
"cd '%MSYS_SOURCE%' && bash build-for-mingw.sh %*"
if %ERRORLEVEL% neq 0 (
echo.
echo Build failed with error code %ERRORLEVEL%.
pause
exit /b %ERRORLEVEL%
)
echo.
echo Build succeeded! Executables are in build-mingw\bin\
pause
-101
View File
@@ -1,101 +0,0 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2026 citron Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Automated MinGW (MSYS2 UCRT64) build script for Citron Neo.
# Run from the MSYS2 UCRT64 shell, or use build-for-mingw.bat to launch it.
set -euo pipefail
# ---------- configuration ----------
BUILD_DIR="${1:-build-mingw}"
BUILD_TYPE="${2:-Release}"
JOBS="${3:-$(nproc)}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SOURCE_DIR="$SCRIPT_DIR"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
ok() { echo -e "${GREEN}[ OK ]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; }
# ---------- environment check ----------
if [[ -z "${MSYSTEM:-}" ]]; then
fail "Not running inside an MSYS2 shell. Use the UCRT64 terminal or build-for-mingw.bat."
fi
if [[ "$MSYSTEM" != "UCRT64" ]]; then
warn "MSYSTEM is '$MSYSTEM', expected 'UCRT64'. Builds may use the wrong toolchain."
fi
command -v pacman >/dev/null 2>&1 || fail "pacman not found — is this really MSYS2?"
# ---------- dependency installation ----------
info "Installing / updating build tools and dependencies via pacman …"
PACKAGES=(
# build tools
mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-ninja
mingw-w64-ucrt-x86_64-toolchain
# required libraries
mingw-w64-ucrt-x86_64-boost
mingw-w64-ucrt-x86_64-fmt
mingw-w64-ucrt-x86_64-nlohmann-json
mingw-w64-ucrt-x86_64-opus
mingw-w64-ucrt-x86_64-SDL2
mingw-w64-ucrt-x86_64-qt6-base
mingw-w64-ucrt-x86_64-qt6-multimedia
mingw-w64-ucrt-x86_64-qt6-svg
mingw-w64-ucrt-x86_64-qt6-tools
mingw-w64-ucrt-x86_64-ffmpeg
mingw-w64-ucrt-x86_64-openal
mingw-w64-ucrt-x86_64-vulkan-headers
mingw-w64-ucrt-x86_64-vulkan-utility-libraries
mingw-w64-ucrt-x86_64-vulkan-memory-allocator
mingw-w64-ucrt-x86_64-libusb
mingw-w64-ucrt-x86_64-enet
mingw-w64-ucrt-x86_64-stb
)
pacman -S --needed --noconfirm "${PACKAGES[@]}" || fail "pacman install failed"
ok "All dependencies installed."
# ---------- configure ----------
info "Configuring CMake (${BUILD_TYPE}) in ${BUILD_DIR}"
mkdir -p "${SOURCE_DIR}/${BUILD_DIR}"
cd "${SOURCE_DIR}/${BUILD_DIR}"
cmake "$SOURCE_DIR" -G Ninja \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DCITRON_USE_BUNDLED_VCPKG=OFF \
-DCITRON_USE_BUNDLED_SDL2=OFF \
-DCITRON_USE_BUNDLED_QT=OFF \
-DCITRON_USE_BUNDLED_FFMPEG=OFF \
-DCITRON_USE_EXTERNAL_VULKAN_HEADERS=OFF \
-DCITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES=OFF \
-DENABLE_QT_TRANSLATION=OFF \
-DUSE_DISCORD_PRESENCE=OFF \
-DCITRON_TESTS=OFF \
-DENABLE_WEB_SERVICE=OFF \
-DCITRON_USE_FASTER_LD=OFF \
|| fail "CMake configuration failed"
ok "CMake configuration succeeded."
# ---------- build ----------
info "Building with ${JOBS} parallel jobs …"
ninja -j"$JOBS" || fail "Build failed"
ok "Build complete!"
echo ""
info "Executables are in: ${SOURCE_DIR}/${BUILD_DIR}/bin/"
ls -lh "${SOURCE_DIR}/${BUILD_DIR}/bin/"*.exe 2>/dev/null || true
echo ""
ok "Done. You can run citron from: ${BUILD_DIR}/bin/citron.exe"
-174
View File
@@ -1,174 +0,0 @@
# SPDX-FileCopyrightText: 2025 citron Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# Fix PGO DLL Script for Citron (Windows)
# This script helps locate and copy the required pgort140.dll for MSVC PGO builds
param(
[Parameter()]
[string]$OutputDir = "build\bin\Release",
[Parameter()]
[switch]$Help
)
function Show-Usage {
Write-Host @"
Usage: .\fix-pgo-dll.ps1 [OPTIONS]
This script helps fix the "pgort140.DLL was not found" error by locating
and copying the required PGO runtime DLL to your build output directory.
Options:
-OutputDir PATH Target directory to copy DLL (default: build\bin\Release)
-Help Show this help message
Example:
.\fix-pgo-dll.ps1
.\fix-pgo-dll.ps1 -OutputDir "C:\MyBuild\bin"
"@
}
function Write-Header {
param([string]$Message)
Write-Host "`n=================================================================" -ForegroundColor Cyan
Write-Host $Message -ForegroundColor Cyan
Write-Host "=================================================================`n" -ForegroundColor Cyan
}
function Write-Info {
param([string]$Message)
Write-Host "[INFO] $Message" -ForegroundColor Green
}
function Write-Warning {
param([string]$Message)
Write-Host "[WARNING] $Message" -ForegroundColor Yellow
}
function Write-Error-Custom {
param([string]$Message)
Write-Host "[ERROR] $Message" -ForegroundColor Red
}
if ($Help) {
Show-Usage
exit 0
}
Write-Header "PGO DLL Fixer for Citron"
# Find Visual Studio installation
$VSInstallPath = $null
$VSWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $VSWhere) {
Write-Info "Searching for Visual Studio installations..."
$VSInstallPath = & $VSWhere -latest -property installationPath
if ($VSInstallPath) {
Write-Info "Found Visual Studio at: $VSInstallPath"
}
} else {
Write-Warning "vswhere.exe not found. Trying common installation paths..."
}
# Common Visual Studio installation paths
$CommonPaths = @(
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Community",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Professional",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise",
"${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Community",
"${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Professional",
"${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Enterprise"
)
if (-not $VSInstallPath) {
foreach ($path in $CommonPaths) {
if (Test-Path $path) {
$VSInstallPath = $path
Write-Info "Found Visual Studio at: $VSInstallPath"
break
}
}
}
if (-not $VSInstallPath) {
Write-Error-Custom "Visual Studio installation not found!"
Write-Host "Please ensure Visual Studio 2019 or 2022 is installed with C++ support."
Write-Host "You can download it from: https://visualstudio.microsoft.com/downloads/"
exit 1
}
# Search for pgort140.dll
Write-Info "Searching for pgort140.dll..."
$DllPaths = @(
"$VSInstallPath\VC\Redist\MSVC\*\x64\Microsoft.VC*.CRT\pgort140.dll",
"$VSInstallPath\VC\Redist\MSVC\*\x86\Microsoft.VC*.CRT\pgort140.dll",
"$VSInstallPath\VC\Tools\MSVC\*\bin\Hostx64\x64\pgort140.dll",
"$VSInstallPath\VC\Tools\MSVC\*\bin\Hostx64\x86\pgort140.dll",
"$VSInstallPath\VC\Tools\MSVC\*\bin\Hostx86\x64\pgort140.dll",
"$VSInstallPath\VC\Tools\MSVC\*\bin\Hostx86\x86\pgort140.dll"
)
$FoundDll = $null
foreach ($pattern in $DllPaths) {
$matches = Get-ChildItem -Path $pattern -ErrorAction SilentlyContinue
if ($matches) {
$FoundDll = $matches[0].FullName
Write-Info "Found pgort140.dll at: $FoundDll"
break
}
}
if (-not $FoundDll) {
Write-Error-Custom "pgort140.dll not found in Visual Studio installation!"
Write-Host "This usually means:"
Write-Host "1. Visual Studio was installed without PGO support"
Write-Host "2. You need to install the 'MSVC v143 - VS 2022 C++ x64/x86 build tools' component"
Write-Host "3. Try repairing your Visual Studio installation"
Write-Host ""
Write-Host "To fix this:"
Write-Host "1. Open Visual Studio Installer"
Write-Host "2. Click 'Modify' on your Visual Studio installation"
Write-Host "3. Go to 'Individual components' tab"
Write-Host "4. Search for 'PGO' and ensure it's checked"
Write-Host "5. Click 'Modify' to install the component"
exit 1
}
# Create output directory if it doesn't exist
if (-not (Test-Path $OutputDir)) {
Write-Info "Creating output directory: $OutputDir"
New-Item -ItemType Directory -Force -Path $OutputDir | Out-Null
}
# Copy the DLL
try {
Write-Info "Copying pgort140.dll to: $OutputDir"
Copy-Item -Path $FoundDll -Destination $OutputDir -Force
Write-Info "Successfully copied pgort140.dll!"
# Verify the copy
$CopiedDll = Join-Path $OutputDir "pgort140.dll"
if (Test-Path $CopiedDll) {
Write-Info "Verification: pgort140.dll is now available in $OutputDir"
Write-Host ""
Write-Host "You can now run your PGO instrumented Citron build!"
} else {
Write-Error-Custom "Failed to copy pgort140.dll"
exit 1
}
} catch {
Write-Error-Custom "Error copying pgort140.dll: $($_.Exception.Message)"
exit 1
}
Write-Header "PGO DLL Fix Complete!"
Write-Info "The pgort140.dll has been copied to your build output directory."
Write-Info "Your PGO instrumented Citron build should now run without the DLL error."
Write-Host ""
Write-Info "Next steps:"
Write-Host "1. Run your PGO instrumented build"
Write-Host "2. Play games to collect profile data"
Write-Host "3. Rebuild with PGO USE stage for optimization"
-344
View File
@@ -1,344 +0,0 @@
# SPDX-FileCopyrightText: 2025 citron Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# PGO Build Script for Citron (Windows/PowerShell)
# This script automates the Profile-Guided Optimization build process
param(
[Parameter(Position=0, Mandatory=$true)]
[ValidateSet('generate', 'use', 'clean', 'merge', 'summary')]
[string]$Stage,
[Parameter()]
[int]$Jobs = 0,
[Parameter()]
[switch]$EnableLTO,
[Parameter()]
[switch]$Help
)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$BuildDir = Join-Path $ScriptDir "build"
$PgoProfilesDir = Join-Path $BuildDir "pgo-profiles"
$BackupProfilesDir = Join-Path $ScriptDir "pgo-profiles-backup"
function Show-Usage {
Write-Host @"
Usage: .\pgo-build.ps1 [STAGE] [OPTIONS]
STAGE can be:
generate - Build with PGO instrumentation (Stage 1)
use - Build using PGO profile data (Stage 2)
clean - Clean build directory but preserve profiles
merge - Merge PGC files into PGD without rebuilding
summary - Show profile coverage statistics
Example workflow:
.\pgo-build.ps1 generate # Build instrumented version
# Run citron.exe, play 2-3 games for 5-10 min each, exit cleanly
.\pgo-build.ps1 merge # Merge collected profiles
.\pgo-build.ps1 summary # Check coverage
.\pgo-build.ps1 use # Build optimized version
Options:
-Jobs N Number of parallel jobs (default: auto-detect)
-EnableLTO Enable Link-Time Optimization
-Help Show this help message
"@
}
function Write-Header {
param([string]$Message)
Write-Host "`n=================================================================" -ForegroundColor Cyan
Write-Host $Message -ForegroundColor Cyan
Write-Host "=================================================================`n" -ForegroundColor Cyan
}
function Write-Info {
param([string]$Message)
Write-Host "[INFO] $Message" -ForegroundColor Green
}
function Write-Warning {
param([string]$Message)
Write-Host "[WARNING] $Message" -ForegroundColor Yellow
}
function Write-Error-Custom {
param([string]$Message)
Write-Host "[ERROR] $Message" -ForegroundColor Red
}
function Find-Pgomgr {
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vswhere) {
$vsPath = & $vswhere -latest -property installationPath
$pgomgr = Get-ChildItem -Path "$vsPath\VC\Tools\MSVC" -Recurse -Filter "pgomgr.exe" -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -match "Hostx64\\x64" } |
Select-Object -First 1
if ($pgomgr) { return $pgomgr.FullName }
}
$found = Get-Command pgomgr.exe -ErrorAction SilentlyContinue
if ($found) { return $found.Source }
return $null
}
function Clean-StaleProfiles {
if (-not (Test-Path $PgoProfilesDir)) { return }
$pgcFiles = Get-ChildItem -Path $PgoProfilesDir -Filter "*.pgc" -ErrorAction SilentlyContinue
if ($pgcFiles -and $pgcFiles.Count -gt 0) {
Write-Info "Removing $($pgcFiles.Count) stale PGC file(s)..."
$pgcFiles | Remove-Item -Force
}
}
function Merge-Profiles {
$pgomgr = Find-Pgomgr
if (-not $pgomgr) {
Write-Warning "pgomgr.exe not found. Cannot merge profiles."
Write-Info "Ensure Visual Studio Build Tools are installed and on PATH."
return $false
}
$pgdFiles = Get-ChildItem -Path $PgoProfilesDir -Filter "*.pgd" -ErrorAction SilentlyContinue
if (-not $pgdFiles -or $pgdFiles.Count -eq 0) {
Write-Warning "No PGD files found in $PgoProfilesDir"
return $false
}
$pgcFiles = Get-ChildItem -Path $PgoProfilesDir -Filter "*.pgc" -ErrorAction SilentlyContinue
if (-not $pgcFiles -or $pgcFiles.Count -eq 0) {
Write-Info "No PGC files to merge."
return $true
}
foreach ($pgd in $pgdFiles) {
Write-Info "Merging PGC files into $($pgd.Name)..."
& $pgomgr /merge $pgd.FullName
if ($LASTEXITCODE -ne 0) {
Write-Warning "pgomgr /merge returned exit code $LASTEXITCODE for $($pgd.Name)"
}
}
# Clean PGC files after successful merge
Write-Info "Cleaning merged PGC files..."
Get-ChildItem -Path $PgoProfilesDir -Filter "*.pgc" -ErrorAction SilentlyContinue | Remove-Item -Force
return $true
}
function Show-ProfileSummary {
$pgomgr = Find-Pgomgr
if (-not $pgomgr) {
Write-Warning "pgomgr.exe not found. Cannot show summary."
return
}
$pgdFiles = Get-ChildItem -Path $PgoProfilesDir -Filter "*.pgd" -ErrorAction SilentlyContinue
if (-not $pgdFiles -or $pgdFiles.Count -eq 0) {
Write-Warning "No PGD files found in $PgoProfilesDir"
return
}
foreach ($pgd in $pgdFiles) {
Write-Header "Profile Summary: $($pgd.Name)"
& $pgomgr /summary $pgd.FullName
Write-Host ""
}
}
if ($Help) {
Show-Usage
exit 0
}
# Auto-detect number of processors
if ($Jobs -eq 0) {
$Jobs = $env:NUMBER_OF_PROCESSORS
if (-not $Jobs) { $Jobs = 4 }
}
$LtoFlag = if ($EnableLTO) { "ON" } else { "OFF" }
# --- Clean stage ---
if ($Stage -eq "clean") {
Write-Header "Cleaning Build Directory"
if (Test-Path $PgoProfilesDir) {
Write-Info "Backing up PGO profiles..."
New-Item -ItemType Directory -Force -Path $BackupProfilesDir | Out-Null
Copy-Item -Path "$PgoProfilesDir\*" -Destination $BackupProfilesDir -Recurse -Force -ErrorAction SilentlyContinue
}
if (Test-Path $BuildDir) {
Write-Info "Removing build directory..."
Remove-Item -Path $BuildDir -Recurse -Force
}
if (Test-Path $BackupProfilesDir) {
Write-Info "Restoring PGO profiles..."
New-Item -ItemType Directory -Force -Path $PgoProfilesDir | Out-Null
Move-Item -Path "$BackupProfilesDir\*" -Destination $PgoProfilesDir -Force -ErrorAction SilentlyContinue
Remove-Item -Path $BackupProfilesDir -Recurse -Force
}
Write-Info "Clean complete!"
exit 0
}
# --- Merge stage ---
if ($Stage -eq "merge") {
Write-Header "Merging PGO Profiles"
if (-not (Test-Path $PgoProfilesDir)) {
Write-Error-Custom "Profile directory not found: $PgoProfilesDir"
exit 1
}
$result = Merge-Profiles
if ($result) {
Write-Info "Merge complete! Run '.\pgo-build.ps1 summary' to check coverage."
} else {
Write-Error-Custom "Merge failed."
exit 1
}
exit 0
}
# --- Summary stage ---
if ($Stage -eq "summary") {
Write-Header "PGO Profile Summary"
if (-not (Test-Path $PgoProfilesDir)) {
Write-Error-Custom "Profile directory not found: $PgoProfilesDir"
exit 1
}
Show-ProfileSummary
exit 0
}
# --- Generate stage ---
if ($Stage -eq "generate") {
Write-Header "PGO Stage 1: Generate Profile Data"
# Clean stale PGC files from any previous run
if (Test-Path $PgoProfilesDir) {
Clean-StaleProfiles
}
# Create build directory
New-Item -ItemType Directory -Force -Path $BuildDir | Out-Null
Set-Location $BuildDir
# Configure
Write-Info "Configuring CMake..."
cmake .. `
-DCITRON_ENABLE_PGO_GENERATE=ON `
-DCITRON_ENABLE_LTO=$LtoFlag `
-DCMAKE_BUILD_TYPE=Release
if ($LASTEXITCODE -ne 0) {
Write-Error-Custom "CMake configuration failed"
exit 1
}
# Build
Write-Info "Building instrumented Citron (this may take a while)..."
cmake --build . --config Release -j $Jobs
if ($LASTEXITCODE -ne 0) {
Write-Error-Custom "Build failed"
exit 1
}
Write-Header "Build Complete!"
Write-Host ""
Write-Host " Training guide for best PGO results:" -ForegroundColor Yellow
Write-Host ""
Write-Host " 1. Run: .\bin\Release\citron.exe"
Write-Host " 2. Launch a game and play PAST initial loading"
Write-Host " (first-time shader compilation is a critical hot path)"
Write-Host " 3. Play for at least 5-10 minutes per game"
Write-Host " 4. Test 2-3 different games for broader code coverage"
Write-Host " 5. Navigate menus, settings, and game list to profile the UI"
Write-Host " 6. Exit citron cleanly (File -> Exit or Ctrl+Q)"
Write-Host ""
Write-Host " After each session, you can run:" -ForegroundColor Yellow
Write-Host " .\pgo-build.ps1 merge # Consolidate collected profiles"
Write-Host " .\pgo-build.ps1 summary # Check profile coverage"
Write-Host ""
Write-Host " When satisfied with coverage, build the optimized binary:" -ForegroundColor Yellow
Write-Host " .\pgo-build.ps1 use"
Write-Host ""
Set-Location $ScriptDir
}
# --- Use stage ---
if ($Stage -eq "use") {
Write-Header "PGO Stage 2: Build Optimized Binary"
# Check if profile data exists
if (-not (Test-Path $PgoProfilesDir) -or -not (Get-ChildItem $PgoProfilesDir -ErrorAction SilentlyContinue)) {
Write-Error-Custom "No profile data found in $PgoProfilesDir"
Write-Info "Please run the generate stage first and collect profile data"
exit 1
}
# Merge any outstanding PGC files before building
Write-Info "Merging any outstanding PGC files..."
Merge-Profiles | Out-Null
# Backup profiles if build directory exists
if (Test-Path $BuildDir) {
Write-Info "Backing up PGO profiles..."
New-Item -ItemType Directory -Force -Path $BackupProfilesDir | Out-Null
Copy-Item -Path "$PgoProfilesDir\*" -Destination $BackupProfilesDir -Recurse -Force
Remove-Item -Path $BuildDir -Recurse -Force
}
# Create build directory and restore profiles
New-Item -ItemType Directory -Force -Path $BuildDir | Out-Null
if (Test-Path $BackupProfilesDir) {
New-Item -ItemType Directory -Force -Path $PgoProfilesDir | Out-Null
Move-Item -Path "$BackupProfilesDir\*" -Destination $PgoProfilesDir -Force
Remove-Item -Path $BackupProfilesDir -Recurse -Force
}
Set-Location $BuildDir
# Configure
Write-Info "Configuring CMake..."
cmake .. `
-DCITRON_ENABLE_PGO_USE=ON `
-DCITRON_ENABLE_LTO=$LtoFlag `
-DCMAKE_BUILD_TYPE=Release
if ($LASTEXITCODE -ne 0) {
Write-Error-Custom "CMake configuration failed"
Set-Location $ScriptDir
exit 1
}
# Build
Write-Info "Building optimized Citron (this may take a while)..."
cmake --build . --config Release -j $Jobs
if ($LASTEXITCODE -ne 0) {
Write-Error-Custom "Build failed"
Set-Location $ScriptDir
exit 1
}
Write-Header "Build Complete!"
Write-Info "Your optimized Citron binary is ready!"
Write-Info "Location: $BuildDir\bin\Release\citron.exe"
Write-Host ""
Write-Info "This build is optimized for your specific usage patterns."
Set-Location $ScriptDir
}
-328
View File
@@ -1,328 +0,0 @@
#!/bin/bash
# SPDX-FileCopyrightText: 2025 citron Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# PGO Build Script for Citron (Linux/macOS)
# This script automates the Profile-Guided Optimization build process
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BUILD_DIR="${SCRIPT_DIR}/build"
PGO_PROFILES_DIR="${BUILD_DIR}/pgo-profiles"
BACKUP_PROFILES_DIR="${SCRIPT_DIR}/pgo-profiles-backup"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
print_header() {
echo -e "${BLUE}=================================================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}=================================================================${NC}"
}
print_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
show_usage() {
echo "Usage: $0 [STAGE] [OPTIONS]"
echo ""
echo "STAGE can be:"
echo " generate - Build with PGO instrumentation (Stage 1)"
echo " use - Build using PGO profile data (Stage 2)"
echo " clean - Clean build directory but preserve profiles"
echo " merge - Merge profile data (Clang: .profraw -> .profdata)"
echo " summary - Show profile file statistics"
echo ""
echo "Example workflow:"
echo " $0 generate # Build instrumented version"
echo " # Run citron, play 2-3 games for 5-10 min each, exit cleanly"
echo " $0 merge # Merge collected profiles"
echo " $0 summary # Check coverage"
echo " $0 use # Build optimized version"
echo ""
echo "Options:"
echo " -j N Number of parallel jobs (default: auto-detect)"
echo " -lto Enable Link-Time Optimization"
echo " -h Show this help message"
}
clean_stale_profiles() {
if [ ! -d "$PGO_PROFILES_DIR" ]; then
return
fi
local gcda_count
gcda_count=$(find "$PGO_PROFILES_DIR" -name "*.gcda" 2>/dev/null | wc -l)
if [ "$gcda_count" -gt 0 ]; then
print_info "Removing $gcda_count stale .gcda file(s)..."
find "$PGO_PROFILES_DIR" -name "*.gcda" -delete
fi
local profraw_count
profraw_count=$(find "$PGO_PROFILES_DIR" -name "*.profraw" 2>/dev/null | wc -l)
if [ "$profraw_count" -gt 0 ]; then
print_info "Removing $profraw_count stale .profraw file(s)..."
find "$PGO_PROFILES_DIR" -name "*.profraw" -delete
fi
}
merge_clang_profiles() {
if ! command -v llvm-profdata &>/dev/null; then
print_warning "llvm-profdata not found. Cannot merge Clang profiles."
return 1
fi
local profraw_files
profraw_files=$(find "$PGO_PROFILES_DIR" -name "*.profraw" 2>/dev/null)
if [ -z "$profraw_files" ]; then
print_info "No .profraw files to merge."
return 0
fi
local count
count=$(echo "$profraw_files" | wc -l)
print_info "Merging $count .profraw file(s)..."
llvm-profdata merge \
-output="${PGO_PROFILES_DIR}/default.profdata" \
${profraw_files}
print_info "Merged into ${PGO_PROFILES_DIR}/default.profdata"
# Clean raw files after merge
print_info "Cleaning merged .profraw files..."
find "$PGO_PROFILES_DIR" -name "*.profraw" -delete
return 0
}
show_profile_summary() {
if [ ! -d "$PGO_PROFILES_DIR" ]; then
print_warning "Profile directory not found: $PGO_PROFILES_DIR"
return
fi
print_header "Profile Summary"
local profdata="${PGO_PROFILES_DIR}/default.profdata"
if [ -f "$profdata" ]; then
local size
size=$(du -h "$profdata" | cut -f1)
print_info "Clang profile: $profdata ($size)"
if command -v llvm-profdata &>/dev/null; then
llvm-profdata show --counts --all-functions "$profdata" 2>/dev/null | tail -5
fi
fi
local gcda_count
gcda_count=$(find "$PGO_PROFILES_DIR" -name "*.gcda" 2>/dev/null | wc -l)
if [ "$gcda_count" -gt 0 ]; then
print_info "GCC profile files: $gcda_count .gcda files"
local total_size
total_size=$(find "$PGO_PROFILES_DIR" -name "*.gcda" -exec du -ch {} + 2>/dev/null | tail -1 | cut -f1)
print_info "Total .gcda size: $total_size"
fi
local profraw_count
profraw_count=$(find "$PGO_PROFILES_DIR" -name "*.profraw" 2>/dev/null | wc -l)
if [ "$profraw_count" -gt 0 ]; then
print_warning "$profraw_count unmerged .profraw file(s) found. Run '$0 merge' first."
fi
if [ "$gcda_count" -eq 0 ] && [ ! -f "$profdata" ] && [ "$profraw_count" -eq 0 ]; then
print_warning "No profile data found in $PGO_PROFILES_DIR"
fi
}
# Parse arguments
STAGE=""
JOBS=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo "4")
ENABLE_LTO="OFF"
while [[ $# -gt 0 ]]; do
case $1 in
generate|use|clean|merge|summary)
STAGE="$1"
shift
;;
-j)
JOBS="$2"
shift 2
;;
-lto)
ENABLE_LTO="ON"
shift
;;
-h|--help)
show_usage
exit 0
;;
*)
print_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
if [ -z "$STAGE" ]; then
print_error "No stage specified"
show_usage
exit 1
fi
# --- Clean stage ---
if [ "$STAGE" == "clean" ]; then
print_header "Cleaning Build Directory"
if [ -d "$PGO_PROFILES_DIR" ]; then
print_info "Backing up PGO profiles..."
mkdir -p "$BACKUP_PROFILES_DIR"
cp -r "$PGO_PROFILES_DIR"/* "$BACKUP_PROFILES_DIR/" 2>/dev/null || true
fi
if [ -d "$BUILD_DIR" ]; then
print_info "Removing build directory..."
rm -rf "$BUILD_DIR"
fi
if [ -d "$BACKUP_PROFILES_DIR" ]; then
print_info "Restoring PGO profiles..."
mkdir -p "$PGO_PROFILES_DIR"
mv "$BACKUP_PROFILES_DIR"/* "$PGO_PROFILES_DIR/" 2>/dev/null || true
rm -rf "$BACKUP_PROFILES_DIR"
fi
print_info "Clean complete!"
exit 0
fi
# --- Merge stage ---
if [ "$STAGE" == "merge" ]; then
print_header "Merging PGO Profiles"
if [ ! -d "$PGO_PROFILES_DIR" ]; then
print_error "Profile directory not found: $PGO_PROFILES_DIR"
exit 1
fi
merge_clang_profiles
print_info "Done! Run '$0 summary' to check coverage."
exit 0
fi
# --- Summary stage ---
if [ "$STAGE" == "summary" ]; then
show_profile_summary
exit 0
fi
# --- Generate stage ---
if [ "$STAGE" == "generate" ]; then
print_header "PGO Stage 1: Generate Profile Data"
# Clean stale profile data from any previous run
if [ -d "$PGO_PROFILES_DIR" ]; then
clean_stale_profiles
fi
# Create build directory
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
# Configure
print_info "Configuring CMake..."
cmake .. \
-DCITRON_ENABLE_PGO_GENERATE=ON \
-DCITRON_ENABLE_LTO=$ENABLE_LTO \
-DCMAKE_BUILD_TYPE=Release
# Build
print_info "Building instrumented Citron (this may take a while)..."
cmake --build . -j"$JOBS"
print_header "Build Complete!"
echo ""
echo -e "${YELLOW} Training guide for best PGO results:${NC}"
echo ""
echo " 1. Run: ./bin/citron"
echo " 2. Launch a game and play PAST initial loading"
echo " (first-time shader compilation is a critical hot path)"
echo " 3. Play for at least 5-10 minutes per game"
echo " 4. Test 2-3 different games for broader code coverage"
echo " 5. Navigate menus, settings, and game list to profile the UI"
echo " 6. Exit citron cleanly (File -> Exit or Ctrl+Q)"
echo ""
echo -e "${YELLOW} After each session, you can run:${NC}"
echo " $0 merge # Consolidate collected profiles"
echo " $0 summary # Check profile coverage"
echo ""
echo -e "${YELLOW} When satisfied with coverage, build the optimized binary:${NC}"
echo " $0 use"
echo ""
fi
# --- Use stage ---
if [ "$STAGE" == "use" ]; then
print_header "PGO Stage 2: Build Optimized Binary"
# Check if profile data exists
if [ ! -d "$PGO_PROFILES_DIR" ] || [ -z "$(ls -A $PGO_PROFILES_DIR 2>/dev/null)" ]; then
print_error "No profile data found in $PGO_PROFILES_DIR"
print_info "Please run the generate stage first and collect profile data"
exit 1
fi
# Merge any outstanding raw profiles before building
print_info "Merging any outstanding profile data..."
merge_clang_profiles || true
# Backup profiles if build directory exists
if [ -d "$BUILD_DIR" ]; then
print_info "Backing up PGO profiles..."
mkdir -p "$BACKUP_PROFILES_DIR"
cp -r "$PGO_PROFILES_DIR"/* "$BACKUP_PROFILES_DIR/"
rm -rf "$BUILD_DIR"
fi
# Create build directory and restore profiles
mkdir -p "$BUILD_DIR"
if [ -d "$BACKUP_PROFILES_DIR" ]; then
mkdir -p "$PGO_PROFILES_DIR"
mv "$BACKUP_PROFILES_DIR"/* "$PGO_PROFILES_DIR/"
rm -rf "$BACKUP_PROFILES_DIR"
fi
cd "$BUILD_DIR"
# Configure
print_info "Configuring CMake..."
cmake .. \
-DCITRON_ENABLE_PGO_USE=ON \
-DCITRON_ENABLE_LTO=$ENABLE_LTO \
-DCMAKE_BUILD_TYPE=Release
# Build
print_info "Building optimized Citron (this may take a while)..."
cmake --build . -j"$JOBS"
print_header "Build Complete!"
print_info "Your optimized Citron binary is ready!"
print_info "Location: $BUILD_DIR/bin/citron"
echo ""
print_info "This build is optimized for your specific usage patterns."
fi