docs(nix): bring the Nix docs in line with the module, and fix a stale claim they shared
There are three places Nix is documented — the public docs-site, packaging/nix/
README.md, and packaging/README.md — plus the changelog. All had drifted.
STALE CLAIM, and not only for Nix. install.md said the plugin runner's "user unit
ships **disabled** — enable it once you have" something to run. That is true only
of Arch and source installs: the deb postinst and RPM %post both
`systemctl --global enable punktfunk-scripting.service`, and the Bazzite sysext
bakes in a default.target.wants symlink (build-sysext.sh:113). bazzite.md carried
the same claim about its own image. Both corrected, per channel, with the reason
the default flipped — the library scanners are plugins, so a host without the
runner can come up with an empty library — and the `mask`-not-`disable` opt-out
the sysext's own comment documents.
docs-site:
* install.md NixOS — `desktopSession` in the example and explained, the runner
no longer needs enabling, and the host/console line says what autoStart does.
* running-as-a-service.md — "Restart the host with your desktop" documented the
drop-in for packaged installs only; NixOS gets its one-liner beside it.
* bazzite.md — the runner is started for you, not "isn't started".
packaging/nix/README.md:
* option tables gain `desktopSession`, `gamescopeHdr`, `gamescopePackage`, and
the `punktfunk` group next to `input` (both are required — the udev rule
chgrp's the vhci nodes and fails outright if the group was never created).
* "what the module configures" gains the security.wrappers entry, and a note on
why the capability sits on the encode worker and never on the host: a wrapper
raises it into the ambient set, which lands it in the permitted set and fails
KWin's /proc/<pid>/exe readlink identically to a file capability.
* the appliance snippet no longer tells you to put pkgs.gamescope on PATH —
gamescopeHdr does that with the patched build, and desktopSession is called
out as the thing to leave off there.
* a caveat recording that `nix flake check` does not check the module, and the
two rules for editing module-check.nix (assertions stay pure Nix; assert
list-valued unit fields on the lists, not the rendered text).
packaging/README.md: the flake ships five packages, not "host + client".
CHANGELOG.md v0.27.0: a NixOS section covering the comm/session-detection fix, the
module changes including the scripting default flip as an explicit behaviour
change, and the flake-check gap — plus the documentation bullets above.
This commit is contained in:
@@ -65,6 +65,64 @@ code. `PYROWAVE_QUEUE_PRIORITY` keeps its 0.26.0 grammar and is now forwarded **
|
||||
handshake rather than read from the worker's environment, which is sanitized at spawn; one env var
|
||||
still means one thing on both platforms.
|
||||
|
||||
### NixOS — session detection, module defaults, and a CI gate that was never running
|
||||
|
||||
🛑 **The host could not detect any graphical session on NixOS, at all.** The live-session probe
|
||||
matched `/proc/<pid>/comm` exactly against `kwin_wayland` / `gamescope` / `gnome-shell` /
|
||||
`Hyprland`. `comm` is the kernel's name for the **executed file**, truncated to 15 bytes — not
|
||||
`argv[0]` — and nixpkgs wraps essentially every graphical binary: `wrapProgram` moves the real ELF
|
||||
aside to `.<name>-wrapped` and installs a wrapper that `exec -a "$0"`s it. So the kernel reports
|
||||
`.kwin_wayland-w` while `ps` and `pgrep -a` show a perfectly ordinary `kwin_wayland`, because they
|
||||
read argv. Every probe answered `ActiveKind::None` on a running desktop, and nothing downstream
|
||||
could recover: `wayland` logged as `-`, a correct `WAYLAND_DISPLAY` changed nothing, `Auto` returned
|
||||
the *detected* backend so a live KWin already in `available()` was never chosen, and a
|
||||
`PUNKTFUNK_COMPOSITOR` pin turned the miss into a hard error through `pinned_at_a_dead_session`.
|
||||
sway and river survived by accident — nixpkgs' wrapper execs a binary still called `sway`.
|
||||
|
||||
Names are now resolved through `/proc/<pid>/exe`, whose file name is untruncated, with the nixpkgs
|
||||
decoration stripped. Stripping requires **both** the leading `.` and a trailing `-wrapped`, so
|
||||
KWin's own real `kwin_wayland_wrapper` binary keeps its name instead of collapsing into
|
||||
`kwin_wayland` and handing the probe the parent's PID. The `comm` fast path is unchanged for every
|
||||
ordinary distro — one read, no readlink — and no name that matched before can stop matching. Also
|
||||
applied to the foreign-gamescope probe, which had the same defect.
|
||||
|
||||
**Module changes** (`services.punktfunk`):
|
||||
|
||||
- **`host.desktopSession`** *(new, default `false`)* — binds the host to `graphical-session.target`,
|
||||
the declarative form of the `punktfunk-host-desktop-session.conf` drop-in. Without it a
|
||||
Plasma/GNOME restart leaves the host holding a Wayland socket and portal D-Bus connection that
|
||||
died with the old compositor: it still listens, still answers, and every session after that fails
|
||||
at capture. Off by default because an appliance may never reach that target and would be left
|
||||
permanently stopped.
|
||||
- ⚠ **`scripting.autoStart` now defaults ON** *(behaviour change)*, matching the deb `postinst` and
|
||||
RPM `%post`, which both `systemctl --global enable` the runner, and the sysext's baked-in
|
||||
`default.target.wants` symlink. It was opt-in here on the reasoning that the runner is inert until
|
||||
you add automation — untrue since the game-library scanners became plugins, so a NixOS host came
|
||||
up with an empty library and no obvious cause. Opt out with `scripting.autoStart = false` or
|
||||
`systemctl --user mask punktfunk-scripting`.
|
||||
- **Three divergences from the shipped units, ported.** `punktfunk-web` gains
|
||||
`StartLimitIntervalSec=0` (without it, 5 starts / 10 s against `RestartSec=2` gives up permanently
|
||||
after ~10 s — exactly the window before the host's first `serve` writes the mgmt token, so a
|
||||
console enabled before the host's first run stayed dead) and `Restart=always` rather than
|
||||
`on-failure`. `punktfunk-scripting` gains the sandbox the deb/rpm unit has all along
|
||||
(`NoNewPrivileges`, `ProtectSystem=strict`, `ReadWritePaths=%h /tmp`, restricted address families,
|
||||
`PrivateTmp=no`) — it is the one unit that runs arbitrary operator TypeScript by design, and it
|
||||
had been running strictly less confined on NixOS than anywhere else.
|
||||
- A **warning** when the host is enabled and `xdg.portal.enable` is not.
|
||||
|
||||
🛑 **`nix flake check` does not check `nixosModules`** — worth knowing for anyone maintaining a
|
||||
flake. It forces the value and asserts it is a lambda taking an open attribute set, and stops;
|
||||
nix's source still carries `// FIXME: if we have a 'nixpkgs' input, use it to check the module.`
|
||||
Measured: a module with a nonexistent option, a nonexistent `pkgs` attribute **and** a nonexistent
|
||||
`lib` function passes, printing `checking NixOS module ... all checks passed!`. `nix.yml`'s header
|
||||
claimed that leg covered the module; it never had. `checks.<system>.nixos-module`
|
||||
(`packaging/nix/module-check.nix`) now evaluates it against real nixpkgs across four scenarios and
|
||||
asserts on the rendered units, including a guard that the host's `ExecStart` stays on the plain
|
||||
store path while the encode worker points at the wrapper. Its assertions are pure Nix, so
|
||||
instantiation runs them and the existing `--no-build` leg is enough. `punktfunk-gamescope` gains a
|
||||
`build-gamescope` dispatch input — it is on the critical path of every host build yet nothing
|
||||
compiled it, and it tracks nixpkgs' gamescope, so a `flake.lock` bump is what breaks it.
|
||||
|
||||
### Host and client environment variables
|
||||
|
||||
- **`PUNKTFUNK_ENCODE_WORKER`** *(new, host, Linux)* — where to find the encode worker. Resolution
|
||||
@@ -87,6 +145,16 @@ still means one thing on both platforms.
|
||||
- The 0.26.0 user-facing notes describe a privilege that is deliberately not granted. That is the
|
||||
record of what 0.26.0 shipped and is **not** rewritten; the new phrasing — granted to the worker,
|
||||
never to the host — lives in `docs/releases/v0.27.0.md`.
|
||||
- `install.md` **NixOS** documents `desktopSession`, and its `punktfunk-scripting` bullet no longer
|
||||
claims the runner "ships disabled": that was true only of Arch and source installs — apt, dnf, the
|
||||
Bazzite sysext and now the NixOS module all start it, because the library scanners are plugins.
|
||||
`bazzite.md` carried the same stale claim and is corrected. **Running as a service → Restart the
|
||||
host with your desktop** gains the NixOS one-liner beside the drop-in.
|
||||
- `packaging/nix/README.md`: `desktopSession`, `gamescopeHdr`/`gamescopePackage` and the
|
||||
`punktfunk` group added to the option tables; the "what the module configures" list gains the
|
||||
`security.wrappers` entry, with the KWin-identification reasoning for why the capability is on the
|
||||
worker and not the host; and a caveat recording that `nix flake check` does not check the module,
|
||||
plus the two rules for editing `module-check.nix`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -44,8 +44,10 @@ manifest is OpenPGP-signed by packages@unom.io (key `AF245C506F4E4763`, the same
|
||||
RPMs), and `punktfunk-sysext` checks that signature against a key baked into the script before it
|
||||
trusts a single checksum — so it needs `gpg` on the box, and it refuses a feed it can't verify.
|
||||
|
||||
The plugin runner rides along in the image but isn't started: run
|
||||
`systemctl --user enable --now punktfunk-scripting` when you want [plugins](/docs/plugins).
|
||||
The plugin runner rides along in the image and is **started for you** — the image bakes in its
|
||||
`default.target.wants` symlink, because the game-library scanners ship as
|
||||
[plugins](/docs/plugins). To turn it off: `systemctl --user mask punktfunk-scripting` (`mask`, not
|
||||
`disable` — a plain disable cannot remove a symlink that lives in `/usr`).
|
||||
|
||||
From then on:
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ services.punktfunk.host = {
|
||||
enable = true;
|
||||
users = [ "alice" ]; # added to the `input` group, for virtual gamepads
|
||||
openFirewall = true;
|
||||
desktopSession = true; # on a machine you log into — see below
|
||||
settings = { RUST_LOG = "info"; }; # these become host.env
|
||||
};
|
||||
```
|
||||
@@ -108,13 +109,27 @@ services.punktfunk.host = {
|
||||
The module does declaratively what the deb/RPM scriptlets do — the systemd user service, udev rules,
|
||||
kernel modules, sysctl tuning, the firewall ports and `input` group membership — and brings in the
|
||||
web console alongside the host. Because `settings` writes the environment file for you, skip the
|
||||
`host.env` step in [After installing](#after-installing). The user services are defined but not
|
||||
started, so from your graphical session enable the host and the console:
|
||||
`host.env` step in [After installing](#after-installing).
|
||||
|
||||
**Set `desktopSession = true` on any machine somebody logs into.** It ties the host to
|
||||
`graphical-session.target`, so restarting Plasma or GNOME restarts the host with it. Without it the
|
||||
host keeps running against a compositor that no longer exists — still listening, still answering,
|
||||
and failing at capture on every session after that. Leave it off for the headless appliance route
|
||||
(a pinned compositor or a gamescope box), which may never reach that target. Same reasoning, and
|
||||
the same caveats for Sway and Hyprland, as [Restart the host with your
|
||||
desktop](/docs/running-as-a-service#restart-the-host-with-your-desktop).
|
||||
|
||||
The host and console user services are defined but not started (set `autoStart = true` for an
|
||||
appliance), so from your graphical session enable them:
|
||||
|
||||
```sh
|
||||
systemctl --user enable --now punktfunk-host punktfunk-web
|
||||
```
|
||||
|
||||
The plugin runner needs no such step — like the deb and RPM, the module starts it for you, because
|
||||
the game-library scanners ship as plugins. Opt out with
|
||||
`services.punktfunk.scripting.autoStart = false;`.
|
||||
|
||||
The full option reference (client, console and scripting options, GPU driver notes, headless
|
||||
appliance setup) is in
|
||||
[packaging/nix](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/nix/README.md). To
|
||||
@@ -138,14 +153,20 @@ update, run `nix flake update punktfunk` in your flake directory, then `sudo nix
|
||||
For Gaming Mode, add the [Decky plugin](/docs/steam-deck) on top of it. Full client instructions
|
||||
for every device: [Install a Client](/docs/install-client).
|
||||
|
||||
- **`punktfunk-scripting`** — the plugin/script runner. Install it if you want
|
||||
[plugins](/docs/plugins) or [automation](/docs/automation). It's inert until you add something to
|
||||
run, so its user unit ships **disabled** — enable it once you have:
|
||||
- **`punktfunk-scripting`** — the plugin/script runner, behind [plugins](/docs/plugins) and
|
||||
[automation](/docs/automation). The game-library scanners ship as plugins, so a host without the
|
||||
runner can come up with an empty library — which is why **apt, dnf, the Bazzite sysext and the
|
||||
NixOS module all start it for you**. On **Arch** and source installs it is not started, so enable
|
||||
it yourself:
|
||||
|
||||
```sh
|
||||
systemctl --user enable --now punktfunk-scripting
|
||||
```
|
||||
|
||||
To opt out where it *is* on: `systemctl --user mask punktfunk-scripting` (`mask`, not `disable` —
|
||||
a plain disable cannot remove a symlink that lives in `/etc` or `/usr`), or on NixOS
|
||||
`services.punktfunk.scripting.autoStart = false;`.
|
||||
|
||||
## After installing
|
||||
|
||||
These three steps are for the **Linux packages**. On Windows the installer does the equivalent for
|
||||
|
||||
@@ -108,6 +108,12 @@ the host running against a compositor that no longer exists. It keeps listening
|
||||
every session after that fails at capture, which is a confusing way to find out. The drop-in makes a
|
||||
compositor restart a host restart.
|
||||
|
||||
On **NixOS** don't copy anything — the module has the option:
|
||||
|
||||
```nix
|
||||
services.punktfunk.host.desktopSession = true;
|
||||
```
|
||||
|
||||
Skip it on the headless/appliance route below (which has its own session unit), and on **Sway or
|
||||
Hyprland**, which don't hand their session to systemd: they never reach `graphical-session.target`, so
|
||||
the drop-in is harmless there but does nothing. To make the host come and go with the session on
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ The other packaging targets have their own READMEs: [`debian/`](debian/README.md
|
||||
[`arch/`](arch/README.md) (pacman binary repo + PKGBUILD + SteamOS sysext),
|
||||
[`flatpak/`](flatpak/README.md) (the client), [`windows/`](windows/README.md) (host installer +
|
||||
drivers), plus `kde/` and `linux/` helpers. **NixOS / Nix** users get a flake (`flake.nix` at the
|
||||
repo root) with reproducible host + client packages and a `services.punktfunk` NixOS module —
|
||||
see [`nix/README.md`](nix/README.md).
|
||||
repo root) with reproducible `punktfunk-host`, `-client`, `-web`, `-scripting` and `-gamescope`
|
||||
packages plus a `services.punktfunk` NixOS module — see [`nix/README.md`](nix/README.md).
|
||||
|
||||
## What's needed beyond base Fedora
|
||||
|
||||
|
||||
+58
-10
@@ -66,6 +66,7 @@ Add the flake and enable the host and/or client:
|
||||
enable = true;
|
||||
users = [ "alice" ]; # → added to the `input` group for virtual gamepads
|
||||
openFirewall = true; # native + GameStream ports
|
||||
desktopSession = true; # a machine you log into — restart the host with the desktop
|
||||
settings = {
|
||||
PUNKTFUNK_VIDEO_SOURCE = "virtual";
|
||||
RUST_LOG = "info";
|
||||
@@ -85,10 +86,11 @@ Add the flake and enable the host and/or client:
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your graphical session:
|
||||
Then, in your graphical session (the console follows with `punktfunk-web`; the plugin runner is
|
||||
already started for you — see `scripting.autoStart` below):
|
||||
|
||||
```sh
|
||||
systemctl --user enable --now punktfunk-host
|
||||
systemctl --user enable --now punktfunk-host punktfunk-web
|
||||
```
|
||||
|
||||
### Options
|
||||
@@ -101,10 +103,12 @@ systemctl --user enable --now punktfunk-host
|
||||
| `gamestream` | `true` | `serve --gamestream` (Moonlight-compatible). `false` = native-only, more secure. |
|
||||
| `autoStart` | `false` | Add the user service to `default.target` (appliance mode — pair with lingering). |
|
||||
| `desktopSession` | `false` | Bind the host to `graphical-session.target` — **turn this on for a machine somebody logs into** (see below). |
|
||||
| `users` | `[ ]` | Users added to the `input` group (virtual gamepads). |
|
||||
| `users` | `[ ]` | Users added to the `input` **and `punktfunk`** groups (virtual gamepads; the second covers the usbip/vhci nodes the virtual Steam Deck pad attaches through — it can emulate arbitrary USB hardware, so list only users you'd trust with that). |
|
||||
| `settings` | `{ }` | `host.env` key/values (see `${package}/share/punktfunk-host/host.env.example`). |
|
||||
| `environmentFile` | `null` | Extra `EnvironmentFile` for secrets (e.g. `PUNKTFUNK_MGMT_TOKEN`); loaded optionally. |
|
||||
| `openFirewall` | `false` | Open the inbound ports (see below). |
|
||||
| `gamescopeHdr` | `true` | Put `punktfunk-gamescope` (gamescope + our `pipewire-hdr` patches) on the service PATH, so a 10-bit client can stream true HDR10 off a gamescope output. Costs a gamescope build from source — set `false` to skip it and stay SDR on that backend. |
|
||||
| `gamescopePackage` | flake's | The patched gamescope used when `gamescopeHdr = true`. |
|
||||
| `package` | flake's | Override the package. |
|
||||
|
||||
**`desktopSession` — set it on a desktop, leave it off on an appliance.** On a machine somebody logs
|
||||
@@ -178,19 +182,36 @@ on a *user* unit needs unprivileged user namespaces; drop it with
|
||||
Everything the RPM's `%install` + `%post` do, declaratively:
|
||||
|
||||
- **systemd `--user` service** `punktfunk-host` → `serve [--gamestream]`, `EnvironmentFile` from
|
||||
`settings` (+ optional secret file), `Restart=on-failure`.
|
||||
`settings` (+ optional secret file), `Restart=on-failure`, and — with `desktopSession` —
|
||||
`PartOf=graphical-session.target`.
|
||||
- **udev rules** (`60-punktfunk.rules`): `/dev/uinput` + `/dev/uhid` group access and the vhci
|
||||
sysfs perms for the virtual Steam Deck.
|
||||
- **kernel modules**: `uinput`, `uhid`, `vhci-hcd` (usbip transport so Steam Input adopts the
|
||||
virtual Deck).
|
||||
- **sysctl**: `net.core.{r,w}mem_max = 32 MB` (high-bitrate UDP headroom; `mkDefault`).
|
||||
- **`input` group** membership for `users`.
|
||||
- **`input` and `punktfunk` groups**, declared and joined for `users`. Both are required: the udev
|
||||
rule `chgrp punktfunk`s the vhci nodes and fails outright if nothing ever created that group.
|
||||
- **A `security.wrappers` entry for `punktfunk-encode-worker`** carrying `cap_sys_nice=ep`, with
|
||||
`PUNKTFUNK_ENCODE_WORKER` pointed at it. A file capability cannot live on a read-only store path,
|
||||
so a wrapper is the only mechanism NixOS has. The capability is deliberately **not** on the host
|
||||
itself — see the caveat below.
|
||||
- **`hardware.graphics.enable = true`** (`mkDefault`) so `/run/opengl-driver/lib` has the driver
|
||||
libs the binaries `dlopen`.
|
||||
- **firewall** (when `openFirewall`): native UDP 9777/5353 + TCP 47990; with `gamestream` also TCP
|
||||
47984/47989/48010 + UDP 47998/47999/48000. The media data plane is an ephemeral, hole-punched
|
||||
UDP port — nothing fixed to open.
|
||||
47984/47989/48010 + UDP 47998/47999/48000; with the console, TCP 47992 + 47993. The media data
|
||||
plane is an ephemeral, hole-punched UDP port — nothing fixed to open.
|
||||
- **tray autostart** entry (`--autostart`; self-gates to users who actually run a host).
|
||||
- **A warning** if `xdg.portal.enable` is off (see the portal note above).
|
||||
|
||||
> **Why the capability is on the worker and not the host.** KWin only advertises its restricted
|
||||
> protocols (`zkde_screencast_unstable_v1` for the virtual output, `org_kde_kwin_fake_input` for
|
||||
> input) to a client it can *identify*, by resolving that client's `/proc/<pid>/exe` and matching an
|
||||
> installed `.desktop`'s `Exec=`. The kernel refuses that readlink to any reader whose effective set
|
||||
> is not a superset of the target's permitted set, and KWin holds no capabilities. A NixOS wrapper
|
||||
> does not dodge this — it raises the capability into the ambient set before exec'ing, which lands
|
||||
> it in the permitted set and fails the readlink identically. Giving the host `cap_sys_nice` broke
|
||||
> desktop streaming on every KDE box in 0.26.0-1. The encode worker is a separate binary that
|
||||
> nothing ever has to identify, so the grant is safe there.
|
||||
|
||||
### GPU drivers (out of scope of the module — set these yourself)
|
||||
|
||||
@@ -213,8 +234,15 @@ services.punktfunk.host = {
|
||||
settings = { PUNKTFUNK_COMPOSITOR = "gamescope"; }; # appliance-only; omit to auto-detect
|
||||
};
|
||||
users.users.streamer.linger = true;
|
||||
# For the gamescope/KWin backends extend the service PATH, e.g.:
|
||||
# systemd.user.services.punktfunk-host.path = [ pkgs.gamescope ];
|
||||
```
|
||||
|
||||
Leave `desktopSession` off here — an appliance starts its own compositor and may never reach
|
||||
`graphical-session.target`, which would leave the host permanently stopped. `gamescopeHdr` (on by
|
||||
default) already puts the patched `punktfunk-gamescope` on the service PATH, so the gamescope
|
||||
backend needs no PATH surgery; extend it only for a helper the module doesn't know about:
|
||||
|
||||
```nix
|
||||
# systemd.user.services.punktfunk-host.path = [ pkgs.some-helper ];
|
||||
```
|
||||
|
||||
The `${package}/share/punktfunk-host/headless/` helpers (KDE/Sway session scripts, example
|
||||
@@ -311,10 +339,30 @@ The shell exports an
|
||||
to consume a prebuilt Skia offline (a fixed-output derivation of the rust-skia tarball) or a
|
||||
vendored from-source Skia build — a tracked follow-up.
|
||||
|
||||
- **⚠ `nix flake check` does NOT check the NixOS module — that is why `module-check.nix` exists.**
|
||||
For `nixosModules`, nix forces the value and asserts it is a lambda taking an open attribute set,
|
||||
and stops there (its source still carries `// FIXME: if we have a 'nixpkgs' input, use it to check
|
||||
the module.`). Measured: a module setting a nonexistent *option*, referencing a nonexistent
|
||||
`pkgs` attribute **and** calling a nonexistent `lib` function passes clean, printing
|
||||
`checking NixOS module 'nixosModules.default'... all checks passed!`. So the reassuring line means
|
||||
nothing. `checks.<system>.nixos-module` (`packaging/nix/module-check.nix`) closes it: it evaluates
|
||||
the module against real nixpkgs in four scenarios and asserts on the rendered systemd units.
|
||||
Two rules if you edit it — **keep every assertion pure Nix** (instantiating the derivation is what
|
||||
runs them, which is what lets the cheap `--no-build` CI leg cover it; a shell script in the
|
||||
`runCommand` body would only run under a full `nix flake check`, i.e. an hour of Rust), and
|
||||
**assert list-valued unit fields on the evaluated lists**, not the rendered text — systemd renders
|
||||
`After=` as one space-separated line, so an `hasInfix` on it silently depends on ordering.
|
||||
|
||||
## Verified
|
||||
|
||||
Both packages build, install, and run on real Nix hardware (NixOS-equivalent: CachyOS + Nix,
|
||||
The packages build, install, and run on real Nix hardware (NixOS-equivalent: CachyOS + Nix,
|
||||
RTX 5070 Ti, driver 610). `punktfunk-host --version` and `punktfunk-session` run; the driver
|
||||
RUNPATH (`/run/opengl-driver/lib`) and the GTK GApps wrapper (GSettings schemas + pixbuf loaders)
|
||||
are present. Fixes discovered during that bring-up: `CMAKE_POLICY_VERSION_MINIMUM=3.5` (CMake ≥ 4),
|
||||
system `libopus` (audiopus_sys), and the session Skia note above.
|
||||
|
||||
In CI (`.gitea/workflows/nix.yml`): `nix flake check --no-build` evaluates every output *including*
|
||||
the module check above, and `punktfunk-web` + `punktfunk-scripting` are built for real. The Rust
|
||||
packages and `punktfunk-gamescope` are `workflow_dispatch` opt-ins (`build-rust`,
|
||||
`build-gamescope`) — run the latter after a `flake.lock` bump, since it patches whatever gamescope
|
||||
the pinned nixpkgs carries.
|
||||
|
||||
Reference in New Issue
Block a user