Oh! Guix! 传说中 GNU/Linux 发行版的终极答案——原子、声明式、完全自由。我用上了,大概两个月。下面这些算不上评测,更像一份折腾笔记。

一、坑多

最大的感受就一个字:坑。比如 Guix 的 search path 机制会把 login bash 的 PATH 重置掉,导致 codex 的 exec_command 找不到它刚注入的 apply_patch;又比如一堆指向 /gnu/store 的环境变量漏进 flatpak 沙盒,让沙盒里的应用直接没网。

Guix 的文档质量其实相当高,但社区人少,很多问题根本搜不到答案。说实话,如果没有 LLM agent,这里面很多坑我是解决不了的。

具体的现象、原因和解决办法我都记在了《Guix 踩坑记录以及解决办法》里,那篇会持续更新。

二、非 FHS

非 FHS 这一点我早有准备,毕竟之前用过 NixOS。而且现在能给 FHS 环境的东西太多了:flatpak、docker/podman、distrobox,Guix 自己的 guix shell 也有 -C-F 选项可以起一个 FHS 容器环境。所以在开发上其实没什么问题。

但是——AppImage 不能正常用,这就相当难受了。

在 NixOS 上,有这些东西:

programs.appimage.enable = true;
programs.appimage.binfmt = true;

还有 appimage-run。而在 Guix 上这些统统没有,官方和社区给出的答案是 guix shell -C -F,再把 dbus、Wayland 之类挂进去,大概长这样:

guix shell \
  --container --network --emulate-fhs \
  --development ungoogled-chromium gcc:lib \
  --preserve='^WAYLAND_DISPLAY$|^XDG_' --expose=$XDG_RUNTIME_DIR \
  --preserve='^DBUS_' --expose=/var/run/dbus \
  -- ./xyz.AppImage

实际使用体验相当糟糕,每次都要手写一长串参数。

顺带一提,guix pack -f appimage 本身也能打包 AppImage,加上 -RR 之后得到的是完整闭包——所有依赖都塞进去,只要目标机器有 FUSE 和 user namespace,不管跑的是 Guix 还是别的发行版都能直接用。我试着打包了 NetEase_Cloud_Music_Gtk4,结果产物接近 1G 🤣,所有编解码器都被打进去了。

三、开发体验:

guix shell 是个很不错的开发工具。配合 direnv,cd 进工作区就能自动把开发工具和依赖注入 PATH。比如我写 Rust 的时候:

❯ cd Projects/gh2tg
direnv: loading ~/Projects/gh2tg/.envrc
direnv: using guix --manifest=manifest.scm
direnv: export +CARGO_HTTP_CAINFO +CPLUS_INCLUDE_PATH +C_INCLUDE_PATH +GUIX_ENVIRONMENT +LIBRARY_PATH +OBJCPLUS_INCLUDE_PATH +OBJC_INCLUDE_PATH +PKG_CONFIG_PATH +RUST_SRC_PATH ~GUIX_LOCPATH ~PATH ~SSL_CERT_DIR ~SSL_CERT_FILE
;; manifest.scm — Rust 开发环境
;;
;; 用法:
;;   guix shell -m manifest.scm
;; 或者把该文件放到项目根目录后直接运行:
;;   guix shell

(specifications->manifest
  (list
    ;; Rust 工具链
    "rust"            ; out 输出:rustc 编译器
    "rust:cargo"      ; Cargo 包管理器
    "rust:tools"      ; rustfmt 等附加开发工具
    "rust:rust-src"   ; 标准库源码(rust-analyzer / IDE 跳转需要)

    ;; 编译链接所需系统工具:提供 cc、ld 等
    "gcc-toolchain"

    ;; 常用开发依赖
    "pkg-config"      ; 供 -sys 类 crate 查找系统库
    "openssl"         ; 很多 crate(如 reqwest、git2)会用到
    "nss-certs"       ; CA 证书,让 cargo 能通过 HTTPS 拉取 crates

    ;; 调试器
    "gdb"))

体验类似于 Nix 的 nix-shell + flakes。另外 guix shell 还能用 -D 指定一个派生,拿到构建这个派生所需的环境,但不安装它本身,调试构建时很好用。

四、GNU 原教旨主义:

Guix 官方 channel 会拒绝打包不是完全自由的软件。比如 PrismLauncher:启动器本身开源,但它的功能只服务于 Minecraft 这个闭源游戏,这种就进不了官方频道。

而且大多数人手里的硬件本来就不完全自由,网卡尤其如此。官方安装镜像只有 Linux-Libre 和 GNU/Hurd 两种内核:Hurd 就不说了,Linux-Libre 根本驱动不了我笔记本的网卡——如果只用官方镜像,我连安装都完不成。

所以我用的是「Guix·萌」镜像,它内置了 nonguix 频道和 Linux 内核。

五、channel 生态:

同样是人少的问题。官方频道打包数量极其有限,而且部分包缺少维护、很久不同步更新。用 Guix 的话,维护一个个人 channel 几乎是必选项——我的频道在 sorubedo/guix-channel

但代价是要添加很多 channel,滚动体验就很差了:各个 channel 之间不会同步,GNU 频道一旦有破坏性更新,大概率会连累其他 channel 的可用性,导致 guix pull 拉不下来或者 guix system reconfigure 直接报错。

而且 Guix 真的很慢,并没有比 Nix 好多少。

还有一个具体的痛点:Flutter 目前相当难用 Guix 打包。它没有对应的 build system,pub.dev 又很难做到不联网(Guix 要求构建阶段离线),我就没找到任何一个 channel 包含任何 Flutter 软件。想自己打包,结果用 AI 也没打出来。

六、桌面体验:

我用的 niri 在官方 channel 有打包,noctalia 也自带 Guix 频道,所以桌面体验这块我感觉和其他发行版大差不差。区别在于,很多组件要去各个 channel 里找,或者自己打包。

我的日常桌面:niri + Noctalia。左边终端是 fastfetch,底下那条命令是 sudo herd status——Guix 的服务管理器是 GNU Shepherd,herd 就是它的控制命令。

我的日常桌面:niri + Noctalia。左边终端是 fastfetch,底下那条命令是 sudo herd status——Guix 的服务管理器是 GNU Shepherd,herd 就是它的控制命令。

过程中也踩了一些坑,比如 (plasma-desktop-service-type) 配出来的 DM 居然是 GDM?不太理解。所以最后我没用桌面服务模块,而是自己组装——这一点和很多元发行版的体验是一致的。组装下来,我对一个日用桌面/WM 到底需要什么,已经相当门清了(

桌面相关的坑我都记在了踩坑记录里:niri 服务与 xdg-desktop-portalXwaylandQt 图标文件管理器,还有 home 侧的 N 卡驱动

七、情绪价值:

Guix 虽然 GNU 血统最纯正,但称得上是一个相当冷门特殊的发行版,甚至被认为属于「灵车」。了解 Guix 的人发现我在用它,大概率会感叹一声「你居然用 Guix」;我也曾因此被误以为是运维大神(。遇到不了解 Guix 的人,我也能好好跟他说道说道声明式 OS 的好处。

但说到底,对于喜欢折腾的人,尝试和折腾各种发行版本来就是一件开心的事。

现代热门发行版已经被 systemd 占领,在 init 和 services 管理这一块几乎没有什么新鲜感。systemd 做得相当好,我也爱用,但不能因此忽视别的 init 的特色。在 non-systemd 发行版里,我用过的还有 Gentoo(OpenRC)、Void(runit)、Alpine 和 postmarketOS。

最令我爽的一次是 Gentoo:通宵等着它编译,从下载镜像到登录 Plasma 花了 9 个小时。再让我来一次我会嫌麻烦,但那种快感很难用语言描述。Guix也是,在装到物理机前,我在虚拟机改了很久配置,装上后的一周又在不断改配置。

结语

Guix 不是给所有人的答案,但它把「声明式」和「完全自由」这两件事推到了极致。这两个月里,我一边被坑得怀疑人生,一边又确实舍不得换掉它。

目前正在考虑回到 Debian Testing,反正 Guix 只要配置声明还在,就能随时复现。

如果你也在用 Guix,欢迎看看我的踩坑记录——那里持续更新我在上面遇到的各种问题和解决办法。

Guix shepherd 服务依赖图

guix system shepherd-graph