diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 76d38cd0..397ee3d8 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -153,12 +153,9 @@ jobs: distro: [ debian, ubuntu_18_04, ubuntu_20_04, ubuntu_21_04, ubuntu_21_10 ] package: [ -p ] extension: [ deb ] - include: # don't package these - - distro: fedora_33 - package: '' - extension: rpm + include: # package these differently - distro: fedora_35 - package: '' + package: '-p' extension: rpm steps: @@ -176,7 +173,7 @@ jobs: - name: Build Linux run: | cd scripts - sudo ./build-sunshine.sh ${{ matrix.package }} -u -n sunshine-${{ matrix.distro }} -s .. + sudo ./build-sunshine.sh ${{ matrix.package }} -e ${{ matrix.extension }} -u -n sunshine-${{ matrix.distro }} -s .. - name: Package Linux if: ${{ matrix.package != '' }} run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index c3a1936e..862e4f1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,6 +313,7 @@ else() set(SUNSHINE_EXECUTABLE_PATH "sunshine") endif() configure_file(gen-deb.in gen-deb @ONLY) + configure_file(gen-rpm.in gen-rpm @ONLY) configure_file(sunshine.desktop.in sunshine.desktop @ONLY) configure_file(sunshine.service.in sunshine.service @ONLY) endif() diff --git a/README.md b/README.md index d61b812c..f062769e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ They make use of docker to handle building Sunshine automatically ### Requirements: -Ubuntu 20.04: +#### Ubuntu 20.04: Install the following: #### Common @@ -52,15 +52,56 @@ On Ubuntu 20.04, the cuda compiler will fail since it's version is too old, it's sudo apt install nvidia-cuda-dev nvidia-cuda-toolkit ``` +#### Fedora 35: + +You will need some things in the RPMFusion repo, nost notably ffmpeg. +``` +sudo dnf install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm +``` +#### Development tools and libraries +``` +sudo dnf install \ + boost-devel \ + boost-static.x86_64 \ + cmake \ + ffmpeg-devel \ + gcc-c++ \ + libevdev-devel \ + libxcb-devel \ + libX11-devel \ + libXcursor-devel \ + libXfixes-devel \ + libXinerama-devel \ + libXi-devel \ + libXrandr-devel \ + libXtst-devel \ + mesa-libGL-devel \ + openssl-devel \ + opus-devel \ + pulseaudio-libs-devel +``` +#### If you need to build an RPM binary package: +``` +sudo dnf install rpmbuild +``` + #### Warning: You might require ffmpeg version >= 4.3. Check the troubleshooting section for more information. ### Compilation: -- `git clone https://github.com/loki-47-6F-64/sunshine.git --recurse-submodules` + +#### Ubuntu +- `git clone https://github.com/SunshineStream/Sunshine.git --recurse-submodules` - `cd sunshine && mkdir build && cd build` - `cmake -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 ..` - `make -j ${nproc}` +#### Fedora +- `git clone https://github.com/SunshineStream/Sunshine.git --recurse-submodules` +- `cd sunshine && mkdir build && cd build` +- `cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ ..` +- `make -j ${nproc}` + ### Setup: sunshine needs access to uinput to create mouse and gamepad events: diff --git a/assets/85-sunshine-rules.rules b/assets/85-sunshine-rules.rules new file mode 100644 index 00000000..46a78a4a --- /dev/null +++ b/assets/85-sunshine-rules.rules @@ -0,0 +1 @@ +KERNEL=="uinput", GROUP="input", MODE="0660" \ No newline at end of file diff --git a/gen-rpm.in b/gen-rpm.in new file mode 100755 index 00000000..e2bec8f4 --- /dev/null +++ b/gen-rpm.in @@ -0,0 +1,179 @@ +#!/bin/sh + +# Export filepaths +export BUILDDIR=@CMAKE_CURRENT_SOURCE_DIR@/build +export BUILDROOT=~/rpmbuild/ +export RPMSRC=~/rpmbuild/SOURCES +export RPMSPEC=~/rpmbuild/SPECS +export RPMBUILD=~/rpmbuild/BUILD + +# Check for Docker switch +if [ "$1" == "-d" ]; then + export DOCKERSTATUS=TRUE +else + export DOCKERSTATUS=FALSE +fi + +# Check if user's rpmbuild folder is there, if so, temoprairly rename it. +if [ -d ~/rpmbuild ]; then + echo "Backing up rpmbuild" + ~/rpmbuild ~/rpmbuild.bkp + export RPMBUILDEXISTS=TRUE +else + export RPMBUILDEXISTS=FALSE +fi + +# Create rpmbuild folder structure +mkdir ~/rpmbuild +mkdir ~/rpmbuild/BUILD +mkdir ~/rpmbuild/BUILDROOT +mkdir ~/rpmbuild/RPMS +mkdir ~/rpmbuild/SOURCES +mkdir ~/rpmbuild/SPECS +mkdir ~/rpmbuild/SRPMS + +# Create sunshine .spec file with preinstall and postinstall scripts +cat << 'EOF' > $RPMSPEC/sunshine.spec +Name: sunshine +Version: @PROJECT_VERSION@ +Release: 1%{?dist} +Summary: An NVIDIA Gamestream-compatible hosting server +BuildArch: x86_64 + +License: GPLv3 +URL: https://github.com/SunshineStream/Sunshine +Source0: sunshine-@PROJECT_VERSION@_bin.tar.gz + +Requires: systemd + +%description +An NVIDIA Gamestream-compatible hosting server + +%pre +#!/bin/sh + +# Sunshine Pre-Install Script +# Store backup for old config files to prevent it from being overwritten +if [ -f /etc/sunshine/sunshine.conf ]; then + cp /etc/sunshine/sunshine.conf /etc/sunshine/sunshine.conf.old +fi + +if [ -f /etc/sunshine/apps_linux.json ]; then + cp /etc/sunshine/apps_linux.json /etc/sunshine/apps_linux.json.old +fi + +%post +#!/bin/sh + +# Sunshine Post-Install Script +export GROUP_INPUT=input + +if [ -f /etc/group ]; then + if ! grep -q $GROUP_INPUT /etc/group; then + echo "Creating group $GROUP_INPUT" + + groupadd $GROUP_INPUT + fi +else + echo "Warning: /etc/group not found" +fi + +if [ -f /etc/sunshine/sunshine.conf.old ]; then + echo "Restoring old sunshine.conf" + mv /etc/sunshine/sunshine.conf.old /etc/sunshine/sunshine.conf +fi + +if [ -f /etc/sunshine/apps_linux.json.old ]; then + echo "Restoring old apps_linux.json" + mv /etc/sunshine/apps_linux.json.old /etc/sunshine/apps_linux.json +fi + +# Update permissions on config files for Web Manager +if [ -f /etc/sunshine/apps_linux.json ]; then + echo "chmod 666 /etc/sunshine/apps_linux.json" + chmod 666 /etc/sunshine/apps_linux.json +fi + +if [ -f /etc/sunshine/sunshine.conf ]; then + echo "chmod 666 /etc/sunshine/sunshine.conf" + chmod 666 /etc/sunshine/sunshine.conf +fi + +# Ensure Sunshine can grab images from KMS +path_to_setcap=$(which setcap) +if [ -x "$path_to_setcap" ] ; then + echo "$path_to_setcap cap_sys_admin+p /usr/bin/sunshine" + $path_to_setcap cap_sys_admin+p /usr/bin/sunshine +fi + +%prep +%setup -q + +%install +rm -rf $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT/%{_bindir} +mkdir -p $RPM_BUILD_ROOT/etc/sunshine +mkdir -p $RPM_BUILD_ROOT/usr/lib/systemd/user +mkdir -p $RPM_BUILD_ROOT/usr/share/applications +mkdir -p $RPM_BUILD_ROOT/etc/udev/rules.d + +cp sunshine $RPM_BUILD_ROOT/%{_bindir}/sunshine +cp sunshine.conf $RPM_BUILD_ROOT/etc/sunshine/sunshine.conf +cp apps_linux.json $RPM_BUILD_ROOT/etc/sunshine/apps_linux.json +cp sunshine.service $RPM_BUILD_ROOT/usr/lib/systemd/user/sunshine.service +cp sunshine.desktop $RPM_BUILD_ROOT/usr/share/applications/sunshine.desktop +cp 85-sunshine-rules.rules $RPM_BUILD_ROOT/etc/udev/rules.d/85-sunshine-rules.rules + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%{_bindir}/sunshine +/usr/lib/systemd/user/sunshine.service +/etc/sunshine/sunshine.conf +/etc/sunshine/apps_linux.json +/usr/share/applications/sunshine.desktop +/etc/udev/rules.d/85-sunshine-rules.rules + +%changelog +* Sat Mar 12 2022 h <65380846+thatsysadmin@users.noreply.github.com> +- Initial packaging of Sunshine. +EOF + +# Copy over sunshine binary and supplemental files into rpmbuild/BUILD/ +mkdir genrpm +mkdir genrpm/sunshine-@PROJECT_VERSION@ +cp sunshine-@PROJECT_VERSION@ genrpm/sunshine-@PROJECT_VERSION@/sunshine +cp sunshine.service genrpm/sunshine-@PROJECT_VERSION@/sunshine.service +cp sunshine.desktop genrpm/sunshine-@PROJECT_VERSION@/sunshine.desktop +cp @CMAKE_CURRENT_SOURCE_DIR@/assets/sunshine.conf genrpm/sunshine-@PROJECT_VERSION@/sunshine.conf +cp @CMAKE_CURRENT_SOURCE_DIR@/assets/apps_linux.json genrpm/sunshine-@PROJECT_VERSION@/apps_linux.json +cp @CMAKE_CURRENT_SOURCE_DIR@/assets/85-sunshine-rules.rules genrpm/sunshine-@PROJECT_VERSION@/85-sunshine-rules.rules +cd genrpm + +# tarball everything as if it was a source file for rpmbuild +tar --create --file sunshine-@PROJECT_VERSION@_bin.tar.gz sunshine-@PROJECT_VERSION@/ +cp sunshine-@PROJECT_VERSION@_bin.tar.gz ~/rpmbuild/SOURCES + +# Use rpmbuild to build the RPM package. +rpmbuild -bb $RPMSPEC/sunshine.spec + +# Check if running in a CT +if [ "$DOCKERSTATUS" == "FALSE" ]; then + # Move the completed RPM into the cmake build folder + mv ~/rpmbuild/RPMS/x86_64/sunshine-@PROJECT_VERSION@-1.fc*.x86_64.rpm @CMAKE_CURRENT_BINARY_DIR@/ + echo "Moving completed RPM package into CMake build folder." +elif [ "$DOCKERSTATUS" == "TRUE" ]; then + # Move into pickup location + mkdir -p /root/sunshine-build/package-rpm/ + mv ~/rpmbuild/RPMS/x86_64/sunshine-@PROJECT_VERSION@-1.fc*.x86_64.rpm /root/sunshine-build/package-rpm/sunshine.rpm + echo "Moving completed RPM package for pickup." +fi + +# Clean up; delete the rpmbuild folder we created and move back the original one +if [ "$RPMBUILDEXISTS" == "TRUE" ]; then + echo "Removing and replacing original rpmbuild folder." + rm -rf ~/rpmbuild + mv ~/rpmbuild.bkp ~/rpmbuild +fi +exit 0 diff --git a/scripts/Dockerfile-debian b/scripts/Dockerfile-debian index 809b20d3..3a53fd9f 100644 --- a/scripts/Dockerfile-debian +++ b/scripts/Dockerfile-debian @@ -35,4 +35,4 @@ RUN apt-get update -y && \ # Entrypoint COPY build-private.sh /root/build.sh -ENTRYPOINT ["/root/build.sh"] +ENTRYPOINT ["/root/build.sh", "-deb"] diff --git a/scripts/Dockerfile-fedora_33 b/scripts/Dockerfile-fedora_33 index a2c8dfa4..50a4e3db 100644 --- a/scripts/Dockerfile-fedora_33 +++ b/scripts/Dockerfile-fedora_33 @@ -18,9 +18,10 @@ RUN dnf -y update && \ openssl-devel \ opus-devel \ pulseaudio-libs-devel \ + rpm-build \ && dnf clean all \ && rm -rf /var/cache/yum # Entrypoint COPY build-private.sh /root/build.sh -ENTRYPOINT ["/root/build.sh"] +ENTRYPOINT ["/root/build.sh", "-rpm"] diff --git a/scripts/Dockerfile-fedora_35 b/scripts/Dockerfile-fedora_35 index ba7abac5..d4f5d843 100644 --- a/scripts/Dockerfile-fedora_35 +++ b/scripts/Dockerfile-fedora_35 @@ -23,9 +23,10 @@ RUN dnf -y update && \ openssl-devel \ opus-devel \ pulseaudio-libs-devel \ + rpm-build \ && dnf clean all \ && rm -rf /var/cache/yum # Entrypoint COPY build-private.sh /root/build.sh -ENTRYPOINT ["/root/build.sh"] +ENTRYPOINT ["/root/build.sh", "-rpm"] diff --git a/scripts/Dockerfile-ubuntu_18_04 b/scripts/Dockerfile-ubuntu_18_04 index b6a05f6f..7225c0c7 100644 --- a/scripts/Dockerfile-ubuntu_18_04 +++ b/scripts/Dockerfile-ubuntu_18_04 @@ -58,4 +58,4 @@ RUN cmake --version # Entrypoint COPY build-private.sh /root/build.sh -ENTRYPOINT ["/root/build.sh"] +ENTRYPOINT ["/root/build.sh", "-deb"] diff --git a/scripts/Dockerfile-ubuntu_20_04 b/scripts/Dockerfile-ubuntu_20_04 index e65f9176..9ae7dfa9 100644 --- a/scripts/Dockerfile-ubuntu_20_04 +++ b/scripts/Dockerfile-ubuntu_20_04 @@ -41,4 +41,4 @@ RUN /root/cuda.run --silent --toolkit --toolkitpath=/usr --no-opengl-libs --no-m # Entrypoint COPY build-private.sh /root/build.sh -ENTRYPOINT ["/root/build.sh"] +ENTRYPOINT ["/root/build.sh", "-deb"] diff --git a/scripts/Dockerfile-ubuntu_21_04 b/scripts/Dockerfile-ubuntu_21_04 index c7c7a3d4..00801c55 100644 --- a/scripts/Dockerfile-ubuntu_21_04 +++ b/scripts/Dockerfile-ubuntu_21_04 @@ -34,4 +34,4 @@ RUN apt-get update -y && \ # Entrypoint COPY build-private.sh /root/build.sh -ENTRYPOINT ["/root/build.sh"] +ENTRYPOINT ["/root/build.sh", "-deb"] diff --git a/scripts/Dockerfile-ubuntu_21_10 b/scripts/Dockerfile-ubuntu_21_10 index 7b51da3d..83b3e7f8 100644 --- a/scripts/Dockerfile-ubuntu_21_10 +++ b/scripts/Dockerfile-ubuntu_21_10 @@ -34,4 +34,4 @@ RUN apt-get update -y && \ # Entrypoint COPY build-private.sh /root/build.sh -ENTRYPOINT ["/root/build.sh"] +ENTRYPOINT ["/root/build.sh", "-deb"] diff --git a/scripts/build-private.sh b/scripts/build-private.sh index 69446de6..93d18748 100755 --- a/scripts/build-private.sh +++ b/scripts/build-private.sh @@ -32,4 +32,17 @@ cmake "-DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE" "-DSUNSHINE_EXECUTABLE_PATH=$SUNSHI make -j ${nproc} -./gen-deb +# Get preferred package format +if [ "$1" == "-rpm" ] +then + echo "Packaging in .rpm format." + ./gen-rpm -d +elif [ "$1" == "-deb" ] +then + echo "Packaging in .deb format." + ./gen-deb +else + echo "Preferred packaging not specified." + echo "Use -deb or -rpm to specify preferred package format." + exit 1 +fi diff --git a/scripts/build-sunshine.sh b/scripts/build-sunshine.sh index df21df3c..5be82808 100755 --- a/scripts/build-sunshine.sh +++ b/scripts/build-sunshine.sh @@ -4,7 +4,8 @@ set -e usage() { echo "Usage: $0" echo " -d: Generate a debug build" - echo " -p: Generate a debian package" + echo " -p: Generate a linux package" + echo " -e: Extension of package... i.e. 'deb', 'rpm' --> default [deb]" echo " -u: The input device is not a TTY" echo " -n name: Docker container name --> default [sunshine]" echo " -s path/to/sources/sunshine: Use local sources instead of a git repository" @@ -26,13 +27,14 @@ absolute_path() { CMAKE_BUILD_TYPE="-e CMAKE_BUILD_TYPE=Release" SUNSHINE_PACKAGE_BUILD=OFF +SUNSHINE_PACKAGE_EXTENSION=deb SUNSHINE_GIT_URL=https://github.com/sunshinestream/sunshine.git CONTAINER_NAME=sunshine # Docker will fail if ctrl+c is passed through and the input is not a tty DOCKER_INTERACTIVE=-ti -while getopts ":dpuhc:s:n:" arg; do +while getopts ":dpuhc:e:s:n:" arg; do case ${arg} in u) echo "Input device is not a TTY" @@ -49,6 +51,21 @@ while getopts ":dpuhc:s:n:" arg; do SUNSHINE_ASSETS_DIR="-e SUNSHINE_ASSETS_DIR=/etc/sunshine" SUNSHINE_EXECUTABLE_PATH="-e SUNSHINE_EXECUTABLE_PATH=/usr/bin/sunshine" ;; + e) + echo "Defining package extension: $OPTARG" + if [ "$OPTARG" == "deb" ] + then + SUNSHINE_PACKAGE_EXTENSION=$OPTARG + echo "Package extension: deb" + elif [ "$OPTARG" == "rpm" ] + then + SUNSHINE_PACKAGE_EXTENSION=$OPTARG + echo "Package extension: rpm" + else + echo "Package extension not supported: $OPTARG" + echo "Falling back to default package extension: $SUNSHINE_PACKAGE_EXTENSION" + fi + ;; s) absolute_path "$OPTARG" OPTARG="$RETURN" @@ -98,8 +115,8 @@ then mkdir -p $BUILD_DIR case $SUNSHINE_PACKAGE_BUILD in ON) - echo "Downloading package to: $BUILD_DIR/$CONTAINER_NAME.deb" - docker cp $CONTAINER_NAME:/root/sunshine-build/package-deb/sunshine.deb "$BUILD_DIR/$CONTAINER_NAME.deb" + echo "Downloading package to: $BUILD_DIR/$CONTAINER_NAME.$SUNSHINE_PACKAGE_EXTENSION" + docker cp $CONTAINER_NAME:/root/sunshine-build/package-$SUNSHINE_PACKAGE_EXTENSION/sunshine.$SUNSHINE_PACKAGE_EXTENSION "$BUILD_DIR/$CONTAINER_NAME.$SUNSHINE_PACKAGE_EXTENSION" ;; *) echo "Downloading binary and assets to: $BUILD_DIR"