news 2026/9/10 15:00:22

niri 发行版打包完全指南:构建选项、桌面会话安装、依赖与测试(Packaging-niri)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
niri 发行版打包完全指南:构建选项、桌面会话安装、依赖与测试(Packaging-niri)

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-configniri-ipcniri-visual-tests,主包名为niri

在 Cargo.toml 中定义的 features 如下:

Feature说明
default默认启用,包含dbussystemdxdp-gnome-screencast
dbus启用 D-Bus 支持(提供各类 freedesktop 与 GNOME 接口、无障碍树、电源键处理)
systemd启用 systemd 集成(全局环境、应用放入 transient scope),隐式依赖dbus
xdp-gnome-screencast通过 xdg-desktop-portal-gnome 启用屏幕录制,隐式依赖dbuspipewire
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-screencast

dinitfeature 在 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-rpmpackage.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-sessionDesktopNames=niri,供登录管理器显示会话选项。

niri-session(resources/niri-session)是会话启动脚本,其逻辑相当完整,值得打包者通读一遍:

  1. 若以用户服务方式运行(存在MANAGERPIDSYSTEMD_EXEC_PID等于当前 PID,且父进程是systemd --user),则直接exec niri --session,把会话管理交给外部 systemd;
  2. 否则检查$SHELL是否在/etc/shells中,以登录 shell 方式重新执行自身;
  3. 优先检测 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_DISPLAYDISPLAYXDG_SESSION_TYPEXDG_CURRENT_DESKTOPNIRI_SOCKET等环境变量;
  4. 若无 systemd 则检测 dinit:校验 dinit 用户守护进程在运行、未启动过的 niri、把登录环境导入 dinit、创建$HOME/.local/share/niri日志目录、dinitctl --user start niri.target,并用dinit-monitor等待其退出;
  5. 两者都没有时提示使用niri --session

niri.service(resources/niri.service)是 systemd 用户单元:Type=notify(niri 会通过 sd-notify 上报就绪)、ExecStart=niri --session,并BindsTo=graphical-session.targetWants=xdg-desktop-autostart.target,保证桌面自启动项在 niri 就绪后运行。

niri-shutdown.target(resources/niri-shutdown.target)用于会话退出时统一停止graphical-session.target及其依赖(StopWhenUnneeded=trueConflicts=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.logdepends-on: dbusresources/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-server

3.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-driversmesa-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" # 然后构建 niri

5.3 完全覆盖版本字符串

你也可以整体覆盖版本字符串,但请确保其中保留对应的 niri 版本号:

export NIRI_BUILD_VERSION_STRING="25.01-1 (e35c630)" # 然后构建 niri

5.4 源码级原理

从源码看,src/utils/mod.rs 中的version()函数依次读取:

  1. 若设置了NIRI_BUILD_VERSION_STRING环境变量,直接原样返回;
  2. 否则取CARGO_PKG_VERSION_MAJOR/MINOR/PATCH,再取NIRI_BUILD_COMMIT;若未设置则回退到git_version!宏(失败时显示"unknown commit");
  3. 组装为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 buildcargo 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 检查要点

对照回溯输出,需要确认三点:

  1. panic 消息存在"overflow when subtracting durations"
  2. 回溯完整走到main,且包含cause_panic帧;
  3. 回溯包含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 特别留意smithaysmithay-drm-extras

如果必须调整某些依赖的版本,请额外关注smithaysmithay-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可以看到完整清单:udevgbmxkbcommonwayland-devellibinputdbus-1systemdlibseatlibdisplay-infopipewire-develpangocairo-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-satellitexdg-desktop-portal-gnomexdg-desktop-portal-gtkgnome-keyring、GPU 驱动、通知守护进程)已尽可能声明;
  • 8 个文件按安装对照表放到正确目录,GDM 中能出现 niri 会话;
  • niri --version输出版本号与提交哈希(而非 "unknown commit");
  • 在不安装 debuginfo 的情况下运行niri panic,回溯能追溯到cause_panic的文件与行号;
  • 测试已排除niri-visual-tests,必要时设置RAYON_NUM_THREADS--test-threads--skip=::eglRUN_SLOW_TESTS=1
  • 依赖锁定在发布版Cargo.lock(尤其是smithaysmithay-drm-extras的 commit);
  • 已生成并安装 bash/fish/zsh 补全脚本。

参考实现:Fedora 的完整打包脚本见 niri.spec.rpkg,可作为其他发行版打包的直接参照。

【免费下载链接】niriA scrollable-tiling Wayland compositor.项目地址: https://gitcode.com/GitHub_Trending/ni/niri

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 14:59:10

Apache Kafka Streams 数据类型与序列化(Serdes)完全指南

Apache Kafka Streams 数据类型与序列化&#xff08;Serdes&#xff09;完全指南 【免费下载链接】Kafka Apache Kafka - A distributed event streaming platform 项目地址: https://gitcode.com/GitHub_Trending/kafka4/kafka 导读 Kafka Streams 作为一个基于 Kafka…

作者头像 李华
网站建设 2026/9/10 14:58:43

COMSOL中手性介质的电磁仿真与应用

1. 手性介质在电磁仿真中的独特价值手性介质&#xff08;Chiral media&#xff09;是一类具有特殊电磁响应的材料&#xff0c;其本构关系中电场与磁场存在交叉耦合。这种特性使得电磁波在传播时会发生偏振面旋转&#xff0c;这种现象被称为光学活性。在COMSOL Multiphysics中模…

作者头像 李华
网站建设 2026/9/10 14:58:39

GTD时间管理法:提升个人生产力的核心技巧

1. 项目概述&#xff1a;为什么《尽管去做》值得一读&#xff1f;这本书的核心价值在于它提供了一套完整的个人生产力管理系统&#xff0c;帮助读者从"想法积压"的状态转变为"高效执行"的模式。作者David Allen提出的GTD&#xff08;Getting Things Done&a…

作者头像 李华