niri 发行版打包完全指南:构建选项、桌面会话安装、依赖与测试(Packaging-niri)
【免费下载链接】niriA scrollable-tiling Wayland compositor.项目地址: https://gitcode.com/GitHub_Trending/ni/niri
导读
niri 是一个可滚动平铺(scrollable-tiling)的 Wayland 合成器。本文面向发行版维护者与打包者,系统讲解如何将 niri 构建为原生二进制、按标准目录布局安装为独立桌面会话(使其出现在 GDM 等登录管理器中)、正确声明运行时依赖、处理版本字符串与 panic 回溯,以及如何在打包环境中运行测试。读完本文,你将能基于当前仓库的源码与resources/下的官方文件,产出符合 niri 上游预期的系统级软件包。
一、构建选项:feature 与默认构建
1.1 从Cargo.toml查看构建特性
打包 niri 的第一步,是查看仓库根目录的 Cargo.toml 中定义的 feature 列表。当前版本的 workspace 成员包括niri-config、niri-ipc与niri-visual-tests,主包名为niri。
在 Cargo.toml 中定义的 features 如下:
| Feature | 说明 |
|---|---|
default | 默认启用,包含dbus、systemd、xdp-gnome-screencast |
dbus | 启用 D-Bus 支持(提供各类 freedesktop 与 GNOME 接口、无障碍树、电源键处理) |
systemd | 启用 systemd 集成(全局环境、应用放入 transient scope),隐式依赖dbus |
xdp-gnome-screencast | 通过 xdg-desktop-portal-gnome 启用屏幕录制,隐式依赖dbus与pipewire |
profile-with-tracy | 启用 Tracy profiler 插桩 |
profile-with-tracy-ondemand | 按需启用的 Tracy profiler 插桩 |
profile-with-tracy-allocations | 启用 Tracy 分配分析 |
dinit | 启用 dinit 集成(全局环境) |
1.2 替换集成目标:systemd 换 dinit
默认 feature 组合(dbus,systemd,xdp-gnome-screencast)对绝大多数发行版来说足够好用。但如果你的发行版使用 dinit 作为服务管理器,可以用下面的命令把 systemd 集成替换为 dinit 集成:
cargo build --release --no-default-features --features dinit,dbus,xdp-gnome-screencastdinitfeature 在 Cargo.toml 中被定义为空 feature(dinit = []),它不额外引入 Rust 依赖,而是配合resources/dinit/下的服务文件使用。
1.3 警告:不要使用--all-features
[!WARNING]切勿以
--all-features构建 niri!部分 feature 仅为开发用途设计。例如
profile-with-tracy*系列会启用把 profiling 数据收集进内存缓冲区的逻辑,该缓冲区会无限增长直到内存耗尽。
这些开发专用 feature 与niri-visual-tests一样,都不应进入发行包。上游在打包脚本 niri.spec.rpkg 中也是只走默认 feature 构建,并显式从测试中排除niri-visual-tests。
二、安装布局:让 niri 成为独立桌面会话
上游推荐把 niri 打包为独立桌面会话(standalone desktop session)。这样安装后 niri 会出现在 GDM 等显示管理器的会话列表中,用户可像选择 GNOME、KDE 一样直接登录 niri。
2.1 文件安装对照表
根据仓库根目录 Cargo.toml 中package.metadata.generate-rpm与package.metadata.deb两段元数据(它们与文档给出的安装布局完全一致),以及 niri.spec.rpkg 中的%install段,标准安装位置如下:
| 文件(构建产物/仓库资源) | 目标目录 |
|---|---|
target/release/niri | /usr/bin/ |
resources/niri-session | /usr/bin/ |
resources/niri.desktop | /usr/share/wayland-sessions/ |
resources/niri-portals.conf | /usr/share/xdg-desktop-portal/ |
resources/niri.service(systemd) | /usr/lib/systemd/user/ |
resources/niri-shutdown.target(systemd) | /usr/lib/systemd/user/ |
resources/dinit/niri(dinit) | /usr/lib/dinit.d/user/ |
resources/dinit/niri.target(dinit) | /usr/lib/dinit.d/user/ |
按上表安装后,/usr/share/wayland-sessions/niri.desktop的存在即会让 GDM 及其他显示管理器识别 niri 会话。
2.2 各资源文件的内容与作用
niri.desktop(resources/niri.desktop)是一个标准的 Desktop Entry,Exec=niri-session,DesktopNames=niri,供登录管理器显示会话选项。
niri-session(resources/niri-session)是会话启动脚本,其逻辑相当完整,值得打包者通读一遍:
- 若以用户服务方式运行(存在
MANAGERPID且SYSTEMD_EXEC_PID等于当前 PID,且父进程是systemd --user),则直接exec niri --session,把会话管理交给外部 systemd; - 否则检查
$SHELL是否在/etc/shells中,以登录 shell 方式重新执行自身; - 优先检测 systemd:检查
niri.service未在运行、systemctl --user reset-failed清理失败状态、import-environment导入登录管理器环境、dbus-update-activation-environment --all同步 D-Bus 环境,然后systemctl --user --wait start niri.service,会话结束时启动niri-shutdown.target(--job-mode=replace-irreversibly),最后清理WAYLAND_DISPLAY、DISPLAY、XDG_SESSION_TYPE、XDG_CURRENT_DESKTOP、NIRI_SOCKET等环境变量; - 若无 systemd 则检测 dinit:校验 dinit 用户守护进程在运行、未启动过的 niri、把登录环境导入 dinit、创建
$HOME/.local/share/niri日志目录、dinitctl --user start niri.target,并用dinit-monitor等待其退出; - 两者都没有时提示使用
niri --session。
niri.service(resources/niri.service)是 systemd 用户单元:Type=notify(niri 会通过 sd-notify 上报就绪)、ExecStart=niri --session,并BindsTo=graphical-session.target、Wants=xdg-desktop-autostart.target,保证桌面自启动项在 niri 就绪后运行。
niri-shutdown.target(resources/niri-shutdown.target)用于会话退出时统一停止graphical-session.target及其依赖(StopWhenUnneeded=true、Conflicts=graphical-session.target graphical-session-pre.target)。
dinit 单元:resources/dinit/niri(resources/dinit/niri)是type = process的服务,command = niri --session,通过ready-notification = pipevar:NOTIFY_FD上报就绪,日志写入$HOME/.local/share/niri/niri.log,depends-on: dbus;resources/dinit/niri.target(resources/dinit/niri.target)是type = internal的目标单元,除依赖 niri 外还会waits-for.d扫描用户与系统的niri.d/目录以加载用户自定义服务。
参考链接:关于发行版集成的进一步说明,见 Integrating niri 页面。
三、推荐依赖:保证开箱即用
3.1libwayland-server:动态加载的核心依赖
首先必须确保 niri 依赖libwayland-server。该库目前是**动态加载(dlopen)**的,因此在 niri 构建期不会被 Cargo 自动纳入依赖清单——打包者必须手动为软件包声明这一运行时依赖。
这在 Fedora 打包脚本 niri.spec.rpkg 中有明确体现:
# Loaded through dlopen Requires: libwayland-server3.2 可选但强烈推荐的依赖
以下依赖是可选的,但上游强烈建议安装,并在可能的情况下将其声明为自动安装的可选依赖(automatically-installed optional dependencies):
xwayland-satellite:运行 X11 应用(Steam、Discord 等)所必需。注意当前仓库采用集成 Xwayland 方案,Fedora 打包脚本中声明Requires: xwayland-satellite >= 0.7(见 niri.spec.rpkg);xdg-desktop-portal-gnome:屏幕录制(screencasting)所必需;xdg-desktop-portal-gtk:在niri-portals.conf中被配置为回退 portal(fallback),属于通常应当安装的标准回退 portal;gnome-keyring:在niri-portals.conf中被配置为 Secret portal 的提供者;- 发行版的 GPU 驱动包,如
mesa-dri-drivers与mesa-libEGL。硬件加速正常工作对运行 niri 是必需条件; - 通知守护进程(如
mako),多数应用依赖其正常工作。
resources/niri-portals.conf 的实际内容印证了上述配置:
[preferred] default=gnome;gtk; org.freedesktop.impl.portal.Access=gtk; org.freedesktop.impl.portal.Notification=gtk; org.freedesktop.impl.portal.Secret=gnome-keyring;3.3 默认配置中绑定的应用
你可能还希望自动安装 niri 默认配置文件 中通过spawn绑定的应用(搜索spawn关键字即可找到),例如终端alacritty与启动器fuzzel。
Fedora 打包脚本的做法是把它们作为弱依赖声明(niri.spec.rpkg):
Recommends: alacritty Recommends: fuzzel Recommends: swaylock Recommends: waybar Recommends: swaybg Recommends: mako Recommends: swayidle四、在打包环境中运行测试
niri 的大部分测试会自行拉起合成器实例并连接测试用 Wayland 客户端,因此不需要图形会话即可运行。但测试采用并行执行,在高核数机器上可能触及文件描述符上限。
如果遇到该问题,需要同时限制 Rust 测试框架的线程数以及 Rayon 的线程数——部分 niri 测试内部使用了 Rayon 线程池:
export RAYON_NUM_THREADS=2 # 然后运行 cargo test,可以搭配 --test-threads=2另外注意:
务必排除仅用于开发的
niri-visual-testscrate。上游打包脚本正是这样做的(niri.spec.rpkg):%cargo_test -- --workspace --exclude niri-visual-tests部分测试需要测试时可用surfaceless EGL。若无法满足,可以跳过它们:
cargo test -- --skip=::egl可以设置环境变量
RUN_SLOW_TESTS=1来运行较慢的测试。
仓库中的测试代码分布可参考 src/layout/tests/、src/tests/ 等目录,其中包含大量 insta 快照(如 niri__tests__window_opening__check_fullscreen_maximize.snap)用于断言窗口布局行为。
五、版本字符串:提交哈希与完整覆盖
5.1 版本字符串的构成
niri 的版本字符串包含版本号与提交哈希:
$ niri --version niri 25.01 (e35c630)在打包系统中构建时通常没有 Git 仓库,提交哈希不可用,版本会显示为 "unknown commit"。
5.2 手工设置提交哈希
这种情况下请手工设置提交哈希:
export NIRI_BUILD_COMMIT="e35c630" # 然后构建 niri5.3 完全覆盖版本字符串
你也可以整体覆盖版本字符串,但请确保其中保留对应的 niri 版本号:
export NIRI_BUILD_VERSION_STRING="25.01-1 (e35c630)" # 然后构建 niri5.4 源码级原理
从源码看,src/utils/mod.rs 中的version()函数依次读取:
- 若设置了
NIRI_BUILD_VERSION_STRING环境变量,直接原样返回; - 否则取
CARGO_PKG_VERSION_MAJOR/MINOR/PATCH,再取NIRI_BUILD_COMMIT;若未设置则回退到git_version!宏(失败时显示"unknown commit"); - 组装为
MAJOR.MINOR (commit)或MAJOR.MINOR.PATCH (commit)格式(patch 为 0 时省略 patch 段)。
Fedora 打包脚本正是通过在.cargo/config.toml的[env]段注入NIRI_BUILD_COMMIT来实现该行为的(见 niri.spec.rpkg)。
5.5 对cargo install的提醒
请记得对cargo build和cargo install都设置这些变量——cargo install在环境变化时会重新构建 niri,若只在构建时设置会导致安装出的二进制版本字符串不对。
六、Panic 回溯:质量验收的硬指标
6.1 为什么需要好的回溯
良好的 panic 回溯对诊断 niri 崩溃至关重要。用户在合成器首次崩溃时通常没有安装 debuginfo 包,因此上游要求:niri 包本身(不安装 debuginfo 或其他包)就应产生良好的回溯。
6.2 用niri panic验证
请使用niri panic命令测试你的包能否产生良好的回溯:
$ niri panic thread 'main' panicked at /builddir/build/BUILD/rust-1.83.0-build/rustc-1.83.0-src/library/core/src/time.rs:1142:31: overflow when subtracting durations stack backtrace: 0: rust_begin_unwind at /builddir/build/BUILD/rust-1.83.0-build/rustc-1.83.0-src/library/std/src/panicking.rs:665:5 1: core::panicking::panic_fmt at /builddir/build/BUILD/rust-1.83.0-build/rustc-1.83.0-src/library/core/src/panicking.rs:74:14 2: core::panicking::panic_display at /builddir/build/BUILD/rust-1.83.0-build/rustc-1.83.0-src/library/core/src/panicking.rs:264:5 3: core::option::expect_failed at /builddir/build/BUILD/rust-1.83.0-build/rustc-1.83.0-src/library/core/src/option.rs:2021:5 4: expect<core::time::Duration> at /builddir/build/BUILD/rust-1.83.0-build/rustc-1.83.0-src/library/core/src/option.rs:933:21 5: sub at /builddir/build/BUILD/rust-1.83.0-build/rustc-1.83.0-src/library/core/src/time.rs:1142:31 6: cause_panic at /builddir/build/BUILD/niri-0.0.git.1699.279c8b6a-build/niri/src/utils/mod.rs:382:13 7: main at /builddir/build/BUILD/niri-0.0.git.1699.279c8b6a-build/niri/src/main.rs:107:27 8: call_once<fn() -> core::result::Result<(), alloc::boxed::Box<dyn core::error::Error, alloc::alloc::Global>>, ()> at /builddir/build/BUILD/rust-1.83.0-build/rustc-1.83.0-src/library/core/src/ops/function.rs:250:5 note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.6.3 检查要点
对照回溯输出,需要确认三点:
- panic 消息存在:
"overflow when subtracting durations"; - 回溯完整走到
main,且包含cause_panic帧; - 回溯包含
cause_panic的文件与行号:at /.../src/utils/mod.rs:382:13。
从当前源码看,cause_panic实现在 src/utils/mod.rs:
#[inline(never)] pub fn cause_panic() { let a = Duration::from_secs(1); let b = Duration::from_secs(2); let _ = a - b; }它刻意构造一次 Duration 减法下溢来触发 panic,且用#[inline(never)]保证回溯中保留独立帧;CLI 侧的命令入口在 src/cli.rs(/// Cause a panic to check if the backtraces are good.的Panic变体)。
6.4 打包实践
为了不依赖 debuginfo 包也能得到好的回溯,Fedora 打包脚本做了两件事(见 niri.spec.rpkg):
- 将
%global debug_package %{nil}与%global __strip /bin/true,不剥离主二进制的调试信息; - 保留 Cargo.toml 中
[profile.release]的debug = "line-tables-only"(见 Cargo.toml),用仅行表的调试信息在体积与可诊断性之间取得平衡。
七、Rust 依赖:离线构建与锁定版本
7.1 使用 vendored 依赖离线构建
每个 niri 发布版都会附带一份由cargo vendor生成的依赖归档,可用于完全离线构建对应版本。若不想使用 vendored 依赖,则应当遵循该发布版附带的 Cargo.lock,其中记录了上游测试该发布版时使用的精确依赖版本。
7.2 特别留意smithay与smithay-drm-extras
如果必须调整某些依赖的版本,请额外关注smithay与smithay-drm-extras的 commit hash。这两个 crate 目前没有常规的稳定版本发布,niri 使用的是 git 快照——在 Cargo.toml 中可以看到它们都指向 Smithay 仓库的同一个rev = "4cf0b62028039661477d482ec4758b687d8f4392"。
由于上游经常发生破坏性变更(API 与行为两方面),强烈建议使用 niri 发布版Cargo.lock中的精确 commit hash。
7.3 构建期系统依赖
打包 niri 还需要一系列构建期系统库。从 niri.spec.rpkg 的BuildRequires可以看到完整清单:udev、gbm、xkbcommon、wayland-devel、libinput、dbus-1、systemd、libseat、libdisplay-info、pipewire-devel、pango、cairo-gobject-devel,以及 pipewire-rs 编译所需的clang和测试用的mesa-libEGL。
八、Shell 补全生成
可以用niri completions <SHELL>为多种 shell 生成补全脚本,例如:
niri completions bash运行niri completions -h可查看完整支持列表。
Fedora 打包脚本在构建后生成 bash、fish、zsh 三套补全并分别安装(niri.spec.rpkg 与%install段):
target/rpm/niri completions bash > ./niri target/rpm/niri completions fish > ./niri.fish target/rpm/niri completions zsh > ./_niri九、打包自检清单
完成打包后,建议逐项核对:
- 以默认 features 构建,未使用
--all-features; libwayland-server已作为运行时依赖声明;- 可选依赖(
xwayland-satellite、xdg-desktop-portal-gnome、xdg-desktop-portal-gtk、gnome-keyring、GPU 驱动、通知守护进程)已尽可能声明; - 8 个文件按安装对照表放到正确目录,GDM 中能出现 niri 会话;
niri --version输出版本号与提交哈希(而非 "unknown commit");- 在不安装 debuginfo 的情况下运行
niri panic,回溯能追溯到cause_panic的文件与行号; - 测试已排除
niri-visual-tests,必要时设置RAYON_NUM_THREADS、--test-threads、--skip=::egl与RUN_SLOW_TESTS=1; - 依赖锁定在发布版
Cargo.lock(尤其是smithay与smithay-drm-extras的 commit); - 已生成并安装 bash/fish/zsh 补全脚本。
参考实现:Fedora 的完整打包脚本见 niri.spec.rpkg,可作为其他发行版打包的直接参照。
【免费下载链接】niriA scrollable-tiling Wayland compositor.项目地址: https://gitcode.com/GitHub_Trending/ni/niri
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考