Nixerus/pkgs/apps/sunshine/sunshine.nix
2026-06-18 17:27:06 +02:00

312 lines
7.8 KiB
Nix

{
lib,
stdenv,
fetchFromGitHub,
fetchzip,
autoPatchelfHook,
autoAddDriverRunpath,
makeWrapper,
buildNpmPackage,
nixosTests,
cmake,
avahi,
libevdev,
libpulseaudio,
libxtst,
libxrandr,
libxi,
libxfixes,
libxdmcp,
libx11,
libxcb,
openssl,
libopus,
boost,
pkg-config,
libdrm,
wayland,
wayland-scanner,
libffi,
libcap,
libgbm,
curl,
pcre,
pcre2,
python3,
libuuid,
libselinux,
libsepol,
libthai,
libdatrie,
libxkbcommon,
libepoxy,
libva,
libvdpau,
libglvnd,
numactl,
amf-headers,
svt-av1,
shaderc,
vulkan-loader,
libappindicator,
libnotify,
pipewire,
miniupnpc,
nlohmann_json,
config,
coreutils,
udevCheckHook,
cudaSupport ? config.cudaSupport,
cudaPackages ? { },
}:
let
inherit (stdenv.hostPlatform) 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";
}
.${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=";
}
.${stdenv.hostPlatform.system};
};
in
stdenv'.mkDerivation (finalAttrs: {
pname = "sunshine";
version = "2026.516.143833";
src = fetchFromGitHub {
owner = "LizardByte";
repo = "Sunshine";
tag = "v${finalAttrs.version}";
hash = "sha256-3yuhOyW1Rqz4ddZ40z2ZzpAReZQFva0SL595XrnFB60=";
fetchSubmodules = true;
};
# build webui
ui = buildNpmPackage {
inherit (finalAttrs) src version;
pname = "sunshine-ui";
npmDepsHash = "sha256-YnNnuAdj/S5LGNytqIsmCApIec8DTWKF6VIJ7AXUctU=";
# use generated package-lock.json as upstream does not provide one
postPatch = ''
cp ${./package-lock.json} ./package-lock.json
'';
installPhase = ''
runHook preInstall
mkdir -p "$out"
cp -a . "$out"/
runHook postInstall
'';
};
postPatch = # don't look for npm since we build webui separately
''
substituteInPlace cmake/targets/common.cmake \
--replace-fail 'find_program(NPM npm REQUIRED)' ""
''
# use system boost instead of FetchContent.
# FETCH_CONTENT_BOOST_USED prevents Simple-Web-Server from re-finding boost
+ ''
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
+ lib.optionalString isLinux ''
substituteInPlace cmake/packaging/linux.cmake \
--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 \
--replace-fail '/usr/bin/env systemctl start --u app-@PROJECT_FQDN@' 'sunshine'
substituteInPlace packaging/linux/app-dev.lizardbyte.app.Sunshine.service.in \
--replace-fail '/bin/sleep' '${lib.getExe' coreutils "sleep"}'
'';
nativeBuildInputs = [
cmake
pkg-config
# 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
]
++ lib.optionals cudaSupport [
autoAddDriverRunpath
cudaPackages.cuda_nvcc
(lib.getDev cudaPackages.cuda_cudart)
];
buildInputs = [
boost
curl
miniupnpc
nlohmann_json
openssl
libopus
]
++ lib.optionals isLinux [
avahi
libevdev
libpulseaudio
libx11
libxcb
libxfixes
libxrandr
libxtst
libxi
libdrm
wayland
libffi
libevdev
libcap
libdrm
pcre
pcre2
libuuid
libselinux
libsepol
libthai
libdatrie
libxdmcp
libxkbcommon
libepoxy
libva
libvdpau
numactl
libgbm
amf-headers
svt-av1
vulkan-loader
pipewire
libappindicator
libnotify
]
++ lib.optionals cudaSupport [
cudaPackages.cudatoolkit
cudaPackages.cuda_cudart
];
runtimeDependencies = lib.optionals isLinux [
avahi
libgbm
libxrandr
libxcb
libglvnd
];
cmakeFlags = [
"-Wno-dev"
(lib.cmakeBool "BOOST_USE_STATIC" false)
(lib.cmakeBool "BUILD_DOCS" false)
(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 [
(lib.cmakeBool "UDEV_FOUND" true)
(lib.cmakeBool "SYSTEMD_FOUND" true)
(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)
];
env = {
# needed to trigger CMake version configuration
BUILD_VERSION = "${finalAttrs.version}";
BRANCH = "master";
COMMIT = "";
};
# copy webui where it can be picked up by build
preBuild = ''
cp -r ${finalAttrs.ui}/build ../
'';
buildFlags = [
"sunshine"
];
# redefine installPhase to avoid attempt to build webui
installPhase = ''
runHook preInstall
cmake --install .
runHook postInstall
'';
# allow Sunshine to find libvulkan
postFixup = lib.optionalString cudaSupport ''
wrapProgram $out/bin/sunshine \
--set LD_LIBRARY_PATH ${lib.makeLibraryPath [ vulkan-loader ]}
'';
doInstallCheck = isLinux;
nativeInstallCheckInputs = lib.optionals isLinux [ udevCheckHook ];
passthru = {
tests = lib.optionalAttrs isLinux {
sunshine = nixosTests.sunshine;
};
updateScript = ./updater.sh;
};
meta = {
description = "Game stream host for Moonlight";
homepage = "https://github.com/LizardByte/Sunshine";
license = lib.licenses.gpl3Only;
mainProgram = "sunshine";
maintainers = [
];
platforms = lib.platforms.linux;
};
})