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-portal、Xwayland、Qt 图标、文件管理器,还有 home 侧的 N 卡驱动。

结语

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

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

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

Guix shepherd 服务依赖图

guix system shepherd-graph