%global build_timestamp %(date +"%Y%m%d") # use sed to replace these values %global build_version 0.4.8 %global branch master %global commit v%{build_version} %undefine _hardened_build %bcond_with cuda %bcond_with tests %global boost_version 1.88.0 %global boost_dir %{_builddir}/boost-%{boost_version}-cmake Name: Apollo Version: %{build_version} Release: 1%{?dist} Summary: A self-hosted game stream server License: GPLv3-only URL: https://github.com/ClassicOldSong/Apollo Source0: %{url}/archive/refs/tags/v%{build_version}.tar.gz BuildRequires: appstream BuildRequires: boost-devel BuildRequires: cmake >= 3.25.0 BuildRequires: desktop-file-utils BuildRequires: libappstream-glib BuildRequires: libayatana-appindicator3-devel BuildRequires: libcap-devel BuildRequires: libcurl-devel BuildRequires: libdrm-devel BuildRequires: libevdev-devel BuildRequires: libgudev BuildRequires: libnotify-devel BuildRequires: libva-devel BuildRequires: libX11-devel BuildRequires: libxcb-devel BuildRequires: libXcursor-devel BuildRequires: libXfixes-devel BuildRequires: libXi-devel BuildRequires: libXinerama-devel BuildRequires: libXrandr-devel BuildRequires: libXtst-devel BuildRequires: git BuildRequires: mesa-libGL-devel BuildRequires: mesa-libgbm-devel BuildRequires: miniupnpc-devel BuildRequires: npm BuildRequires: numactl-devel BuildRequires: openssl-devel BuildRequires: opus-devel BuildRequires: pulseaudio-libs-devel BuildRequires: rpm-build BuildRequires: systemd-udev BuildRequires: systemd-rpm-macros %{?sysusers_requires_compat} BuildRequires: wget BuildRequires: which # for unit tests BuildRequires: xorg-x11-server-Xvfb # Conditional BuildRequires for cuda-gcc based on Fedora version %if 0%{?fedora} <= 41 BuildRequires: gcc13 BuildRequires: gcc13-c++ %global gcc_version 13 %global cuda_version 12.9.1 %global cuda_build 575.57.08 %elif %{?fedora} >= 42 BuildRequires: gcc14 BuildRequires: gcc14-c++ %global gcc_version 14 %global cuda_version 12.9.1 %global cuda_build 575.57.08 %endif %global cuda_dir %{_builddir}/cuda Requires: libayatana-appindicator3 >= 0.5.3 Requires: libcap >= 2.22 Requires: libcurl >= 7.0 Requires: libdrm > 2.4.97 Requires: libevdev >= 1.5.6 Requires: libopusenc >= 0.2.1 Requires: libva >= 2.14.0 Requires: libwayland-client >= 1.20.0 Requires: libX11 >= 1.7.3.1 Requires: miniupnpc >= 2.2.4 Requires: numactl-libs >= 2.0.14 Requires: openssl >= 3.0.2 Requires: pulseaudio-libs >= 10.0 Requires: which >= 2.21 %description A self-hosted game stream server. %prep # extract tarball to current directory git clone --recurse-submodules --branch v%{build_version} %{url}.git %{_builddir}/Apollo # list directory ls -a %{_builddir}/Apollo # prune unwanted vendored copies if present rm -rf \ %{_builddir}/Apollo/packaging/linux/flatpak/deps/flatpak-builder-tools \ %{_builddir}/Apollo/packaging/linux/flatpak/deps/shared-modules \ %{_builddir}/Apollo/third-party/doxyconfig \ %{_builddir}/Apollo/third-party/nv-codec-headers # align names with Apollo branding sed -E -e 's&\bsunshine\b&"apollo"&g' -i %{_builddir}/Apollo/cmake/prep/init.cmake %{_builddir}/Apollo/cmake/packaging/unix.cmake sed -E -e '/set\(PROJECT_FQDN/s&^.*$&set(PROJECT_FQDN "apollo")&' -i %{_builddir}/Apollo/cmake/compile_definitions/linux.cmake sed -E -e 's&\bsunshine\b&apollo&g' -i %{_builddir}/Apollo/cmake/targets/common.cmake # make Boost.Process compatible with Fedora's Boost find %{_builddir}/Apollo/src -type f \( -name "*.h" -o -name "*.cpp" \) -print0 | xargs -0 sed -E -i \ -e 's&boost/process/v1/&boost/process/&g' \ -e 's&boost::process::v1::&boost::process::&g' \ -e 's&boost::process::v1\b&boost::process&g' # disable unwanted macros sed 's¯o(find_package)¯o(_disable_find_package)&' -i %{_builddir}/Apollo/cmake/macros/common.cmake # fix for Boost 1.89 sed -E -e 's&\b(Boost::)?(system)\b&&' -i %{_builddir}/Apollo/third-party/Simple-Web-Server/CMakeLists.txt cat > %{_builddir}/Apollo/cmake/dependencies/Boost_Sunshine.cmake << 'END' include_guard(GLOBAL) find_package(Boost COMPONENTS filesystem locale log program_options) message(STATUS "Boost include dirs: ${Boost_INCLUDE_DIRS}") message(STATUS "Boost libraries: ${Boost_LIBRARIES}") END %build # exit on error set -e # Detect the architecture and Fedora version architecture=$(uname -m) cuda_supported_architectures=("x86_64" "aarch64") # Pre-fetch Boost via CMake FetchContent to get newer headers (boost.process v1) function fetch_boost_cmake() { if [ -f "%{boost_dir}/CMakeLists.txt" ]; then return fi local boost_url="https://github.com/boostorg/boost/releases/download/boost-%{boost_version}/boost-%{boost_version}-cmake.tar.xz" echo "boost url: ${boost_url}" mkdir -p "%{boost_dir}" wget \ "$boost_url" \ --progress=bar:force:noscroll \ --retry-connrefused \ --tries=3 \ -q -O "%{_builddir}/boost-cmake.tar.xz" tar -xf "%{_builddir}/boost-cmake.tar.xz" -C "%{boost_dir}" --strip-components=1 rm -f "%{_builddir}/boost-cmake.tar.xz" } # prepare CMAKE args cmake_args=( "-B=%{_builddir}/Apollo/build" "-G=Unix Makefiles" "-S=." "-DBUILD_DOCS=OFF" "-DBUILD_WERROR=ON" "-DCMAKE_BUILD_TYPE=Release" "-DCMAKE_INSTALL_PREFIX=%{_prefix}" "-DSUNSHINE_ASSETS_DIR=%{_datadir}/apollo" "-DSUNSHINE_EXECUTABLE_PATH=%{_bindir}/apollo" "-DSUNSHINE_ENABLE_WAYLAND=ON" "-DSUNSHINE_ENABLE_X11=ON" "-DSUNSHINE_ENABLE_DRM=ON" "-DSUNSHINE_PUBLISHER_NAME=Apollo" "-DSUNSHINE_PUBLISHER_WEBSITE=https://github.com/ClassicOldSong/Apollo" "-DSUNSHINE_PUBLISHER_ISSUE_URL=https://github.com/ClassicOldSong/Apollo/issues" "-DFETCHCONTENT_SOURCE_DIR_BOOST=%{boost_dir}" ) export CC=gcc-%{gcc_version} export CXX=g++-%{gcc_version} function install_cuda() { # check if we need to install cuda if [ -f "%{cuda_dir}/bin/nvcc" ]; then echo "cuda already installed" return fi local cuda_prefix="https://developer.download.nvidia.com/compute/cuda/" local cuda_suffix="" if [ "$architecture" == "aarch64" ]; then local cuda_suffix="_sbsa" fi local url="${cuda_prefix}%{cuda_version}/local_installers/cuda_%{cuda_version}_%{cuda_build}_linux${cuda_suffix}.run" echo "cuda url: ${url}" wget \ "$url" \ --progress=bar:force:noscroll \ --retry-connrefused \ --tries=3 \ -q -O "%{_builddir}/cuda.run" chmod a+x "%{_builddir}/cuda.run" "%{_builddir}/cuda.run" \ --no-drm \ --no-man-page \ --no-opengl-libs \ --override \ --silent \ --toolkit \ --toolkitpath="%{cuda_dir}" rm "%{_builddir}/cuda.run" # we need to patch math_functions.h on fedora 42+ # see https://forums.developer.nvidia.com/t/error-exception-specification-is-incompatible-for-cospi-sinpi-cospif-sinpif-with-glibc-2-41/323591/3 if [ "%{?fedora}" -ge 42 ]; then echo "Original math_functions.h:" find "%{cuda_dir}" -name math_functions.h -exec cat {} \; # Apply the patch patch -p2 \ --backup \ --directory="%{cuda_dir}" \ --verbose \ < "%{_builddir}/Apollo/packaging/linux/patches/${architecture}/01-math_functions.patch" fi } %if %{with cuda} if [ -n "%{cuda_version}" ] && [[ " ${cuda_supported_architectures[@]} " =~ " ${architecture} " ]]; then install_cuda cmake_args+=("-DSUNSHINE_ENABLE_CUDA=ON") cmake_args+=("-DCMAKE_CUDA_COMPILER:PATH=%{cuda_dir}/bin/nvcc") cmake_args+=("-DCMAKE_CUDA_HOST_COMPILER=gcc-%{gcc_version}") else cmake_args+=("-DSUNSHINE_ENABLE_CUDA=OFF") fi %else cmake_args+=("-DSUNSHINE_ENABLE_CUDA=OFF") %endif # setup the version export BRANCH=%{branch} export BUILD_VERSION=v%{build_version} export COMMIT=%{commit} # cmake fetch_boost_cmake cd %{_builddir}/Apollo echo "cmake args:" echo "${cmake_args[@]}" cmake "${cmake_args[@]}" make -j$(nproc) -C "%{_builddir}/Apollo/build" %if %{with tests} %check # validate the metainfo file appstreamcli validate %{buildroot}%{_metainfodir}/*.metainfo.xml appstream-util validate %{buildroot}%{_metainfodir}/*.metainfo.xml desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop # run tests cd %{_builddir}/Apollo/build xvfb-run ./tests/test_sunshine %endif %install cd %{_builddir}/Apollo/build %make_install # fix desktop file icon name (Icon should not include extension) sed -E -e 's&^(Icon=apollo)\\.svg$&\\1&' -i %{buildroot}%{_datadir}/applications/*.desktop # default config with non-conflicting base port install -Dm644 /dev/stdin %{buildroot}%{_datadir}/apollo/apollo.conf << 'END' port = 49000 END # rename Sunshine artifacts to Apollo to avoid file conflicts rm -f %{buildroot}%{_userunitdir}/sunshine.service for f in %{buildroot}%{_udevrulesdir}/*-sunshine.rules; do if [ -f "$f" ]; then mv "$f" "${f/-sunshine.rules/-apollo.rules}" fi done for f in %{buildroot}%{_modulesloaddir}/*-sunshine.conf; do if [ -f "$f" ]; then mv "$f" "${f/-sunshine.conf/-apollo.conf}" fi done for f in %{buildroot}%{_datadir}/applications/dev.lizardbyte.app.Sunshine*.desktop; do if [ -f "$f" ]; then new_name="${f/dev.lizardbyte.app.Sunshine/apollo}" mv "$f" "$new_name" sed -E -i 's&Sunshine&Apollo&g; s&sunshine&apollo&g' "$new_name" fi done if [ -f %{buildroot}%{_metainfodir}/dev.lizardbyte.app.Sunshine.metainfo.xml ]; then mv %{buildroot}%{_metainfodir}/dev.lizardbyte.app.Sunshine.metainfo.xml %{buildroot}%{_metainfodir}/apollo.metainfo.xml sed -E -i 's&dev.lizardbyte.app.Sunshine&com.github.ClassicOldSong.Apollo&g; s&Sunshine&Apollo&g; s&sunshine&apollo&g' %{buildroot}%{_metainfodir}/apollo.metainfo.xml fi # replace systemd user service to use Apollo config dir install -Dm644 /dev/stdin %{buildroot}%{_userunitdir}/apollo.service << 'END' [Unit] Description=Apollo - Self-hosted game stream host for Moonlight StartLimitIntervalSec=500 StartLimitBurst=5 [Service] ExecStartPre=/usr/bin/sleep 5 ExecStartPre=/usr/bin/sh -c 'test -f %h/.config/apollo/apollo.conf || install -Dm644 /usr/share/apollo/apollo.conf %h/.config/apollo/apollo.conf' ExecStart=/usr/bin/apollo %h/.config/apollo/apollo.conf Restart=on-failure RestartSec=5s [Install] WantedBy=xdg-desktop-autostart.target END %post # Note: this is copied from the postinst script # Load uhid (DS5 emulation) echo "Loading uhid kernel module for DS5 emulation." modprobe uhid # Check if we're in an rpm-ostree environment if [ ! -x "$(command -v rpm-ostree)" ]; then echo "Not in an rpm-ostree environment, proceeding with post install steps." # Trigger udev rule reload for /dev/uinput and /dev/uhid path_to_udevadm=$(which udevadm) if [ -x "$path_to_udevadm" ]; then echo "Reloading udev rules." $path_to_udevadm control --reload-rules $path_to_udevadm trigger --property-match=DEVNAME=/dev/uinput $path_to_udevadm trigger --property-match=DEVNAME=/dev/uhid echo "Udev rules reloaded successfully." else echo "error: udevadm not found or not executable." fi else echo "rpm-ostree environment detected, skipping post install steps. Restart to apply the changes." fi %files # Executables %caps(cap_sys_admin+p) %{_bindir}/apollo %caps(cap_sys_admin+p) %{_bindir}/apollo-* # Systemd unit file for user services %{_userunitdir}/apollo.service # Udev rules %{_udevrulesdir}/*-apollo.rules # Modules-load configuration %{_modulesloaddir}/*-apollo.conf # Desktop entries %{_datadir}/applications/*.desktop # Icons %{_datadir}/icons/hicolor/scalable/apps/apollo.svg %{_datadir}/icons/hicolor/scalable/status/apollo*.svg # Metainfo %{_datadir}/metainfo/*.metainfo.xml # Assets %{_datadir}/apollo/** %changelog