sunshine: 2025.924.154138 -> 2026.516.143833

Adapt the package to upstream's packaging refactor in this release:

- Upstream now downloads a prebuilt ffmpeg from LizardByte/build-deps at
  cmake configure time. Fetch it via fetchzip and point cmake at it with
  FFMPEG_PREPARED_BINARIES. Sunshine pins build-deps via a git submodule
  at third-party/build-deps; the matching release tag is derived from
  that commit. Extend updater.sh to refresh both the tag and the
  per-architecture tarball hashes.
- The boost version pin in cmake/dependencies/Boost_Sunshine.cmake
  bumped to 1.89.0. Switch the substitution to a sed regex so future
  upstream bumps don't break the patch.
- The .desktop file now Exec's `/usr/bin/env systemctl start --u
  app-@PROJECT_FQDN@`; update the replace-fail pattern. The remaining
  @VAR@ placeholders are handled by cmake's configure_file(@ONLY) now.
- packaging/linux/sunshine.service.in was renamed to
  packaging/linux/app-dev.lizardbyte.app.Sunshine.service.in and now
  uses @SUNSHINE_SERVICE_START_COMMAND@/@SUNSHINE_SERVICE_STOP_COMMAND@
  instead of @SUNSHINE_EXECUTABLE_PATH@. Drop the postPatch subst-var-by
  lines and set SUNSHINE_EXECUTABLE_PATH via a cmake flag instead.
- cmake/packaging/linux.cmake now installs the .desktop file itself, so
  the redundant postInstall is removed.
- Add shaderc (glslc), vulkan-loader, and pipewire to inputs, all new
  configure-time requirements.
- glad's generator wants jinja2 + setuptools at configure time. Provide
  them via python3.withPackages and set GLAD_SKIP_PIP_INSTALL=ON so
  cmake doesn't try to pip-install.

Assisted-by: Claude Code 4.7
(cherry picked from commit 391d69d880)
This commit is contained in:
Qubasa 2026-05-19 13:06:05 +02:00 committed by github-actions[bot]
commit eb6e31e2db
3 changed files with 847 additions and 609 deletions

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@
lib,
stdenv,
fetchFromGitHub,
fetchzip,
autoPatchelfHook,
autoAddDriverRunpath,
makeWrapper,
@ -45,9 +46,11 @@
numactl,
amf-headers,
svt-av1,
shaderc,
vulkan-loader,
libappindicator,
libnotify,
pipewire,
miniupnpc,
nlohmann_json,
config,
@ -56,20 +59,53 @@
cudaSupport ? config.cudaSupport,
cudaPackages ? { },
apple-sdk_15,
darwinMinVersionHook,
}:
let
inherit (stdenv.hostPlatform) isDarwin isLinux;
stdenv' = if cudaSupport then cudaPackages.backendStdenv else stdenv;
# Upstream's cmake fetches a pre-built ffmpeg from LizardByte/build-deps at
# configure time. We can't do network I/O during the build, so fetch it via
# a fixed-output derivation and point cmake at it via FFMPEG_PREPARED_BINARIES.
# The tag must match the commit of the third-party/build-deps submodule pinned
# in the Sunshine release.
buildDepsTag = "v2026.516.30821";
ffmpegArch =
{
x86_64-linux = "Linux-x86_64";
aarch64-linux = "Linux-aarch64";
x86_64-darwin = "Darwin-x86_64";
aarch64-darwin = "Darwin-arm64";
}
.${stdenv.hostPlatform.system}
or (throw "sunshine: unsupported system ${stdenv.hostPlatform.system} for prebuilt ffmpeg");
ffmpegPrebuilt = fetchzip {
url = "https://github.com/LizardByte/build-deps/releases/download/${buildDepsTag}/${ffmpegArch}-ffmpeg.tar.gz";
# stripRoot defaults to true; the hash here matches what
# `nix-prefetch-url --unpack` produces, so the updater can refresh it
# with the built-in command (which also caches downloads by URL,
# unlike the empty-hash trick).
hash =
{
x86_64-linux = "sha256-VT+4qP2FaizCoIBBbBkzbYw4YOvGhuBUoZxWL0IYVZo=";
aarch64-linux = "sha256-X5v/GsJy8G3/LHW/8s0VAS0Vegr7JhZSqYotXL/s81o=";
x86_64-darwin = "sha256-rrOGahWwJikRfUn27Q4jVra2Q/MMSNitu0wS2UGKGWk=";
aarch64-darwin = "sha256-xkfwLJgb7uz1H7mJrQFW79w2T/T/Zv7biXlvXz5UvXc=";
}
.${stdenv.hostPlatform.system};
};
in
stdenv'.mkDerivation (finalAttrs: {
pname = "sunshine";
version = "2025.924.154138";
version = "2026.516.143833";
src = fetchFromGitHub {
owner = "LizardByte";
repo = "Sunshine";
tag = "v${finalAttrs.version}";
hash = "sha256-QrPfZqd9pgufohUjxlTpO6V0v7B41UrXHZaESsFjZ48=";
hash = "sha256-3yuhOyW1Rqz4ddZ40z2ZzpAReZQFva0SL595XrnFB60=";
fetchSubmodules = true;
};
@ -77,7 +113,7 @@ stdenv'.mkDerivation (finalAttrs: {
ui = buildNpmPackage {
inherit (finalAttrs) src version;
pname = "sunshine-ui";
npmDepsHash = "sha256-miRw5JGZ8L+CKnoZkCuVW+ptzFV3Dg21zuS9lqNeHro=";
npmDepsHash = "sha256-YnNnuAdj/S5LGNytqIsmCApIec8DTWKF6VIJ7AXUctU=";
# use generated package-lock.json as upstream does not provide one
postPatch = ''
@ -102,8 +138,8 @@ stdenv'.mkDerivation (finalAttrs: {
# use system boost instead of FetchContent.
# FETCH_CONTENT_BOOST_USED prevents Simple-Web-Server from re-finding boost
+ ''
substituteInPlace cmake/dependencies/Boost_Sunshine.cmake \
--replace-fail 'set(BOOST_VERSION "1.87.0")' 'set(BOOST_VERSION "${boost.version}")'
sed -i -E 's/set\(BOOST_VERSION "[^"]*"\)/set(BOOST_VERSION "${boost.version}")/' \
cmake/dependencies/Boost_Sunshine.cmake
echo 'set(FETCH_CONTENT_BOOST_USED TRUE)' >> cmake/dependencies/Boost_Sunshine.cmake
''
# remove upstream dependency on systemd and udev
@ -112,27 +148,31 @@ stdenv'.mkDerivation (finalAttrs: {
--replace-fail 'find_package(Systemd)' "" \
--replace-fail 'find_package(Udev)' ""
# The remaining @VAR@ placeholders in the .desktop file (PROJECT_NAME,
# PROJECT_DESCRIPTION, PROJECT_FQDN, SUNSHINE_DESKTOP_ICON,
# CMAKE_INSTALL_FULL_DATAROOTDIR) are substituted by cmake's
# configure_file(... @ONLY) during the build.
substituteInPlace packaging/linux/dev.lizardbyte.app.Sunshine.desktop \
--subst-var-by PROJECT_NAME 'Sunshine' \
--subst-var-by PROJECT_DESCRIPTION 'Self-hosted game stream host for Moonlight' \
--subst-var-by SUNSHINE_DESKTOP_ICON 'sunshine' \
--subst-var-by CMAKE_INSTALL_FULL_DATAROOTDIR "$out/share" \
--replace-fail '/usr/bin/env systemctl start --u sunshine' 'sunshine'
--replace-fail '/usr/bin/env systemctl start --u app-@PROJECT_FQDN@' 'sunshine'
substituteInPlace packaging/linux/sunshine.service.in \
--subst-var-by PROJECT_DESCRIPTION 'Self-hosted game stream host for Moonlight' \
--subst-var-by SUNSHINE_EXECUTABLE_PATH $out/bin/sunshine \
substituteInPlace packaging/linux/app-dev.lizardbyte.app.Sunshine.service.in \
--replace-fail '/bin/sleep' '${lib.getExe' coreutils "sleep"}'
'';
nativeBuildInputs = [
cmake
pkg-config
python3
# glad's generator needs Jinja2 + setuptools at configure time;
# GLAD_SKIP_PIP_INSTALL=ON tells cmake not to pip-install them.
(python3.withPackages (ps: [
ps.jinja2
ps.setuptools
]))
makeWrapper
]
++ lib.optionals isLinux [
wayland-scanner
shaderc # provides glslc, needed at configure time for shader compilation
# Avoid fighting upstream's usage of vendored ffmpeg libraries
autoPatchelfHook
]
@ -182,6 +222,8 @@ stdenv'.mkDerivation (finalAttrs: {
libgbm
amf-headers
svt-av1
vulkan-loader
pipewire
libappindicator
libnotify
]
@ -191,6 +233,8 @@ stdenv'.mkDerivation (finalAttrs: {
]
++ lib.optionals isDarwin [
apple-sdk_15
# av_audio.mm calls AudioHardwareCreateProcessTap, introduced in macOS 14.2
(darwinMinVersionHook "14.2")
];
runtimeDependencies = lib.optionals isLinux [
@ -208,6 +252,10 @@ stdenv'.mkDerivation (finalAttrs: {
(lib.cmakeFeature "SUNSHINE_PUBLISHER_NAME" "nixpkgs")
(lib.cmakeFeature "SUNSHINE_PUBLISHER_WEBSITE" "https://nixos.org")
(lib.cmakeFeature "SUNSHINE_PUBLISHER_ISSUE_URL" "https://github.com/NixOS/nixpkgs/issues")
# avoid cmake's network download of the LizardByte/build-deps ffmpeg tarball
(lib.cmakeFeature "FFMPEG_PREPARED_BINARIES" "${ffmpegPrebuilt}")
# we provide Jinja2/setuptools via python3.withPackages; don't pip-install
(lib.cmakeBool "GLAD_SKIP_PIP_INSTALL" true)
]
# upstream tries to use systemd and udev packages to find these directories in FHS; set the paths explicitly instead
++ lib.optionals isLinux [
@ -216,6 +264,8 @@ stdenv'.mkDerivation (finalAttrs: {
(lib.cmakeFeature "UDEV_RULES_INSTALL_DIR" "lib/udev/rules.d")
(lib.cmakeFeature "SYSTEMD_USER_UNIT_INSTALL_DIR" "lib/systemd/user")
(lib.cmakeFeature "SYSTEMD_MODULES_LOAD_DIR" "lib/modules-load.d")
# used in the generated systemd unit's ExecStart= line
(lib.cmakeFeature "SUNSHINE_EXECUTABLE_PATH" "${placeholder "out"}/bin/sunshine")
]
++ lib.optionals (!cudaSupport) [
(lib.cmakeBool "SUNSHINE_ENABLE_CUDA" false)
@ -252,10 +302,6 @@ stdenv'.mkDerivation (finalAttrs: {
runHook postInstall
'';
postInstall = lib.optionalString isLinux ''
install -Dm644 ../packaging/linux/dev.lizardbyte.app.Sunshine.desktop $out/share/applications/dev.lizardbyte.app.Sunshine.desktop
'';
# allow Sunshine to find libvulkan
postFixup = lib.optionalString cudaSupport ''
wrapProgram $out/bin/sunshine \

View file

@ -1,20 +1,127 @@
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p gnugrep curl jq nix-update
#! nix-shell -i bash -p gnugrep gnused coreutils curl jq nix-update nix-prefetch-git
# shellcheck shell=bash
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/../../../.."
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
package_nix="$script_dir/package.nix"
nixpkgs_root="$(cd "$script_dir/../../../.." && pwd)"
cd "$nixpkgs_root"
version=$(curl ${GITHUB_TOKEN:+-u ":$GITHUB_TOKEN"} --silent --location https://api.github.com/repos/LizardByte/Sunshine/releases/latest | jq --raw-output .tag_name | grep -oP "^v\K.*")
log() {
printf '\n==> %s\n' "$*" >&2
}
api() {
curl ${GITHUB_TOKEN:+-u ":$GITHUB_TOKEN"} --silent --location "$@"
}
log "Querying latest Sunshine release from GitHub"
version=$(api https://api.github.com/repos/LizardByte/Sunshine/releases/latest | jq --raw-output .tag_name | grep -oP "^v\K.*")
log "Latest version: $version"
if [[ "${UPDATE_NIX_OLD_VERSION:-}" == "$version" ]]; then
echo "Already up to date!"
log "Already up to date!"
exit 0
fi
nix-update sunshine --version "$version"
log "Updating sunshine version (src hash refreshed separately, see below)"
# --no-src: nix-update can't fetch submodules, so we refresh the src hash
# ourselves via nix-prefetch-git below.
nix-update sunshine --version "$version" --no-src
log "Prefetching sunshine src with submodules (this can take several minutes)"
# nix-prefetch-git outputs SRI under .hash on recent versions. The submodule
# tree NAR-hashes identically on Linux and Darwin, so one hash serves both.
src_hash=$(nix-prefetch-git \
--quiet \
--fetch-submodules \
--url "https://github.com/LizardByte/Sunshine" \
--rev "v$version" \
| jq --raw-output .hash)
if [[ -z "$src_hash" || "$src_hash" == "null" ]]; then
echo "ERROR: failed to prefetch sunshine src hash" >&2
exit 1
fi
log "src hash: $src_hash"
log "Patching src hash in $package_nix"
# The src fetchFromGitHub is the only one with fetchSubmodules; anchor on it so
# we don't touch the ffmpeg or npmDepsHash entries. sed -z spans newlines.
sed -i -zE "s#hash = \"sha256-[A-Za-z0-9+/=]+\"(\\s*fetchSubmodules = true;)#hash = \"$src_hash\"\\1#" "$package_nix"
if ! grep -q "$src_hash" "$package_nix"; then
echo "ERROR: failed to write src hash into $package_nix" >&2
exit 1
fi
log "Regenerating sunshine.ui package-lock.json"
# `--generate-lockfile` only regenerates package-lock.json; it skips the npmDepsHash
# refresh (see nix-update's dependency_hashes.py). Run a second pass to update the hash.
nix-update sunshine --version=skip --generate-lockfile --subpackage ui
nix-update sunshine --version=skip --subpackage ui
# `--no-src` avoids re-fetching the (already-pinned) sunshine src on each pass.
nix-update sunshine --version=skip --no-src --generate-lockfile --subpackage ui
log "Refreshing sunshine.ui npmDepsHash"
nix-update sunshine --version=skip --no-src --subpackage ui
# Update the LizardByte/build-deps tag and pinned ffmpeg tarball hashes.
# Sunshine pins build-deps via a git submodule at third-party/build-deps; the
# tag we need is whichever build-deps release tag points at that submodule's
# commit.
log "Resolving LizardByte/build-deps submodule commit and tag"
build_deps_sha=$(api "https://api.github.com/repos/LizardByte/Sunshine/contents/third-party?ref=v$version" \
| jq --raw-output '.[] | select(.name=="build-deps") | .sha')
log "build-deps submodule commit: $build_deps_sha"
build_deps_tag=$(api "https://api.github.com/repos/LizardByte/build-deps/tags?per_page=100" \
| jq --raw-output --arg sha "$build_deps_sha" '.[] | select(.commit.sha==$sha) | .name' \
| head -n1)
if [[ -z "$build_deps_tag" ]]; then
echo "ERROR: no LizardByte/build-deps tag points at submodule commit $build_deps_sha" >&2
exit 1
fi
log "build-deps tag: $build_deps_tag"
# Compute the SRI hash of a `fetchzip` (default stripRoot=true) for a URL.
# `nix-prefetch-url --unpack` produces the same NAR hash AND caches by URL
# (whereas the empty-hash + fetchzip trick re-downloads every invocation).
prefetch_unpacked_sri() {
local raw
raw=$(nix-prefetch-url --unpack --type sha256 "$1")
nix --extra-experimental-features nix-command hash convert --hash-algo sha256 --to sri "$raw"
}
ffmpeg_url() {
echo "https://github.com/LizardByte/build-deps/releases/download/$build_deps_tag/$1-ffmpeg.tar.gz"
}
# Map nix system → upstream tarball arch token. Keep this in sync with the
# `ffmpegArch` attrset in package.nix.
declare -A ffmpeg_arch=(
[x86_64-linux]=Linux-x86_64
[aarch64-linux]=Linux-aarch64
[x86_64-darwin]=Darwin-x86_64
[aarch64-darwin]=Darwin-arm64
)
declare -A ffmpeg_hash
for system in "${!ffmpeg_arch[@]}"; do
log "Prefetching ffmpeg tarball for $system (${ffmpeg_arch[$system]})"
h=$(prefetch_unpacked_sri "$(ffmpeg_url "${ffmpeg_arch[$system]}")")
if [[ -z "$h" ]]; then
echo "ERROR: failed to prefetch ffmpeg tarball for $system" >&2
exit 1
fi
log " $system -> $h"
ffmpeg_hash[$system]=$h
done
log "Patching $package_nix"
sed_args=(-E -e "s#buildDepsTag = \"v[^\"]*\";#buildDepsTag = \"$build_deps_tag\";#")
for system in "${!ffmpeg_hash[@]}"; do
sed_args+=(-e "s#$system = (lib\\.fakeHash|\"sha256-[A-Za-z0-9+/=]+\");#$system = \"${ffmpeg_hash[$system]}\";#")
done
sed -i "${sed_args[@]}" "$package_nix"
log "Done."