NixOS 15.09 "Dingo" 发布解读:Haskell NG、自动升级与向后兼容变更实战指南
【免费下载链接】nixpkgs Nix Packages collection & NixOS 项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgs
本指南以 NixOS 15.09(代号 "Dingo",2015/09/30 发布)官方发布说明为主体,梳理该版本的核心技术亮点与所有向后不兼容变更,并结合当前 Nixpkgs 仓库源码验证各特性的现代实现与演进路径。读完本文,你将掌握:system.autoUpgrade 自动升级的完整用法、system.stateVersion 兼容性机制的原理、Haskell NG 包基础设施的操作方法,以及从 15.09 升级时需要处理的全部兼容性改动。
版本总览:15.09 的核心技术栈
NixOS 15.09 是继 14.12 之后的一个重要版本,除了大量新增与升级的软件包之外,官方发布说明强调以下五个层面:基础工具链升级、全新重构的 Haskell 包基础设施、系统自动升级能力、桌面环境全面换代,以及一大批新服务的引入。
该版本基于以下基础组件构建:
- Glibc 2.21
- GCC 4.9
- Linux 3.18
- Nix 1.10(新增二进制缓存加密签名支持)
桌面环境方面:GNOME 升级至 3.16,Xfce 升级至 4.12,KDE 5 升级至 KDE Frameworks 5.10 + Plasma 5.3.2 + Applications 15.04.3,KDE 4 更新至 kdelibs-4.14.10,E19(Enlightenment)升级至 0.16.8.15。
Haskell NG:Hackage 全量打包的包基础设施
15.09 最重要的架构级变化是 Haskell 包基础设施的重设计("Haskell NG")。NixOS 现在分发 Hackage 上注册的每一个软件包的最新版本——超过 8,000 个 Haskell 包,并且额外提供了 51 个 Haskell 包集合,覆盖从 0.0 开始的每一个 LTS Haskell 版本,以及最新的 Stackage Nightly 快照。
查询与安装 Haskell 包
由于 Haskell 包集规模巨大,nix-env -qa 不再按名称发现 Haskell 包,全局命名空间下只暴露 ghc、cabal-install 和 stack 三个顶层属性,其余包全部隐藏。列出 Haskell 包列表需使用属性路径过滤:
nix-env -f "<nixpkgs>" -qaP -A haskellPackages
安装用 Haskell 编写的可执行程序:
nix-env -f "<nixpkgs>" -iA haskellPackages.pandoc
但通过这种方式安装 Haskell 库已不再被支持,详见下文 ghc-wrapper 移除一节。
构建 Haskell 环境的现代形态:ghcWithPackages
15.09 中 ghc-wrapper(一个让 GHC 透明加载用户 profile 中库的小脚本)被废弃并从发行版中移除。向编译器注册 Haskell 库的正确方式是 haskellPackages.ghcWithPackages 函数。该函数在 make-package-set.nix 中定义,由 with-packages-wrapper.nix 实现:它通过包装编译器可执行文件并注入正确的环境变量,为指定的一组包构建一个自包含的 GHC 环境。示例用法:
haskellPackages.ghcWithPackages (p: with p; [ lens conduit aeson ])
同时需要留意:所有用 1.x 版本 cabal2nix 生成的 Haskell 构建结果在 15.09 中均已失效,必须用当前版本的 cabal2nix 重新生成。安装方式:
nix-env -i cabal2nix
另外,haskellPackages 集合中原本用于在 ~/.nixpkgs/config.nix 中配置额外属性的 extension 函数属性,现已更名为 overrides(功能不变)。
Haskell 生态的其他调整
- Elm 不再发布在 Hackage 上,应改用 elmPackages.elm(包含最新 Elm platform)。
- 引入模块参数时需注意:Haskell 包不再占用顶层属性空间,这是出于查询性能的权衡——若将整个 Hackage 数据库加入顶层属性集,nix-env -qa 等按名称查询操作会变得极其缓慢。
自动升级:system.autoUpgrade
15.09 起,你可以让 NixOS 系统自动保持最新,只需在 configuration.nix 中设置:
{ system.autoUpgrade.enable = true; }
系统会定期检查当前 channel 的更新并运行 nixos-rebuild。其现代实现在 auto-upgrade.nix 中,核心机制是一个每天触发一次的 systemd timer 运行 nixos-rebuild switch –upgrade。该模块(源码可查)提供了丰富的调优选项:
- system.autoUpgrade.enable:布尔值,默认 false,是否启用每日自动升级。
- system.autoUpgrade.operation:枚举 "switch"(默认)或 "boot",决定执行 nixos-rebuild switch –upgrade 还是 nixos-rebuild boot –upgrade。
- system.autoUpgrade.channel:channel 的 URI,默认使用 nix-channel 设定的当前 channel(可用 nix-channel –list 查看)。
- system.autoUpgrade.flake:NixOS 配置的 Flake URI(如 github:kloenk/nix),设置后禁用 channel 选项。
- system.autoUpgrade.upgrade:布尔值,默认 true,当未设置 channel 时控制是否附加 –upgrade 参数(例如按 flake lockfile 升级时)。
- system.autoUpgrade.flags:额外传给 nixos-rebuild 的参数列表,如 ["-I" "stuff=/home/alice/nixos-stuff" "–option" …]。
system.stateVersion:跨版本升级的兼容性锚点
15.09 引入了一个沿用至今的机制——system.stateVersion。其作用是:当某些配置变更可能破坏现有系统(例如 sshd 主机密钥设置)时,通过该选项声明你最初安装的 NixOS 版本,从而保持与该版本行为兼容。
官方发布说明中的使用示例:
{ system.stateVersion = "14.12"; }
该选项的现代实现位于 version.nix,其中明确了若干约束:
- 取值必须匹配 YY.MM 格式(如 15.09),否则触发断言失败。
- 版本控制机制的精神在于:让此类包/服务的默认版本条件化于首次安装的 NixOS 版本,而不是简单地跟随最新。
- 官方警示:升级系统时不要改动 system.stateVersion,它并不会帮助你完成升级,只用于保持旧行为兼容。
- 若未显式设置,会回退到当前发行版本的默认值并给出提示(说明为什么需要关注该选项)。
安全与基础组件变更
sshd 不再默认支持 DSA/ECDSA 主机密钥
从 15.09 起,sshd 默认不再支持 DSA 和 ECDSA 主机密钥。已存在此类主机密钥的系统如需继续使用,必须设置 system.stateVersion = "14.12"(即上文机制的实际应用场景之一)。NixOps 会自动为已有部署设置 state version。
Nix 1.10:二进制缓存强制签名
Nix 升级到 1.10 后,要求二进制缓存必须使用加密签名(改进安全性)。如果你仍想使用未签名的二进制缓存,需设置:
nix.requireSignedBinaryCaches = false;
该选项的现代实现映射关系见 nix.nix:legacyConfMappings 将 requireSignedBinaryCaches 映射到 Nix 配置键 require-sigs。同表还映射了 binaryCaches → substituters、binaryCachePublicKeys → trusted-public-keys 等新旧配置键名。
OpenSSH moduli 文件可替换
针对 2015 年初披露的 Diffie-Hellman 密钥交换漏洞,担心 /etc/ssh/moduli 质量的 SSH 服务器管理员,可以使用新的 services.openssh.moduliFile 选项,用自己生成的 moduli 文件替换 OpenSSH 默认版本。该选项在现代仓库中已被重命名为 services.openssh.settings.ModuliFile(通过 mkRenamedOptionModule 兼容迁移,见 sshd.nix),说明发布说明中的旧选项名至今仍能通过重命名机制生效。
服务与系统组件的新增
新增 NixOS 服务模块(可验证源码路径)
以下服务模块自 15.09 起加入发行版,其中多数在当前仓库中仍存在,可直接在 module-list.nix 中查阅并启用:
| 邮件 | services/mail/exim.nix |
| 通用 misc | apache-kafka、canto-daemon、confd、devmon、gitit、ihaskell、mbpfan、mediatomb、mwlib、parsoid、plex、ripple-rest、ripple-data-api、subsonic、sundtek |
| 监控 | cadvisor、das_watchdog、grafana.nix、riemann-tools、teamviewer |
| 网络文件系统 | u9fs |
| 网络 | aiccu、asterisk、bird.nix、charybdis、docker-registry-server、fan、firefox/sync-server、gateone、heyefi、i2p、lambdabot、mstpd、nix-serve、nylon、racoon、skydns、shout、softether、sslh、tinc、tlsdated、tox-bootstrapd、tvheadend、zerotierone |
| 调度 | marathon |
| 安全 | fprintd.nix、hologram、munge |
| 系统 | cloud-init |
| Web 服务 | shellinabox、uwsgi |
| X11 | unclutter、sddm(现代路径为 services/display-managers/sddm.nix) |
新增系统模块
- system/boot/coredump.nix:systemd coredump 支持。
- system/boot/loader/loader.nix:引导加载器抽象。
- system/boot/loader/generic-extlinux-compatible:通用 extlinux 兼容引导。
- system/boot/networkd.nix:systemd-networkd 集成(当前仍在 system/boot/networkd.nix)。
- system/boot/resolved.nix:systemd-resolved DNS 解析(system/boot/resolved.nix)。
- system/boot/timesyncd.nix:systemd-timesyncd 时间同步。
新增文件系统与虚拟化支持
- tasks/filesystems/exfat.nix:exFAT 文件系统支持(tasks/filesystems/exfat.nix)。
- tasks/filesystems/ntfs.nix:NTFS 支持。
- tasks/filesystems/vboxsf.nix:VirtualBox 共享文件夹文件系统(tasks/filesystems/vboxsf.nix),详见下文 VirtualBox 小节。
- virtualisation/virtualbox-host.nix:VirtualBox 主机支持(virtualisation/virtualbox-host.nix)。
- virtualisation/vmware-guest.nix、virtualisation/xen-dom0.nix:VMware guest 与 Xen dom0(virtualisation/xen-dom0.nix)。
升级前必读:向后不兼容变更清单
以下是官方发布说明列出的全部不兼容变更,升级 15.09 前请逐一核对。
cron 不再默认启用
除非你配置了非空的 services.cron.systemCronJobs,否则 cron 不再默认启用。强制启用方式:
services.cron.enable = true;
现代实现见 cron.nix:services.cron.enable 默认 false,且当存在任意 systemCronJobs 时通过 mkDefault 自动启用(第 97 行)。也就是说,在 15.09 之后的版本中,只要有模块往 systemCronJobs 里写了任务,cron 就会自动打开。
Steam 不再需要 root
Steam 现在无需 root 权限即可运行。不再使用 *-steam-chrootenv,直接运行 steam 即可。包名发生了互换:steamChrootEnv 更名为 steam,原来的 steam 更名为 steamOriginal。
包重命名
- CMPlayer 上游更名为 bomi,包 cmplayer 相应改名为 bomi。
- Atom Shell 上游更名为 Electron,包 atom-shell 相应改名为 electron。
CUPS 打印服务更新
CUPS 更新至 2.0.2,systemd 服务更名为 cups.service。行为变更:本地打印机默认不再共享或广播。需要共享或浏览时分别启用:
services.printing.defaultShared = true; # 共享打印机
services.printing.browsing = true; # 浏览/广播打印机
VirtualBox 选项更名与 vboxsf 共享文件夹
VirtualBox 主机与 guest 选项命名更一致:
- services.virtualboxHost.* → virtualisation.virtualbox.host.*
- services.virtualboxGuest.* → virtualisation.virtualbox.guest.*
同时新增对 vboxsf 文件系统的支持,可直接通过 fileSystems 配置挂载共享文件夹:
{
fileSystems."/shiny" = {
device = "myshinysharedfolder";
fsType = "vboxsf";
};
}
现代实现中,virtualbox-guest.nix 的 virtualisation.virtualbox.guest.vboxsf 选项会在启用时设置 boot.supportedFilesystems = [ "vboxsf" ] 并创建 vboxsf 用户组(gid 73,见 ids.nix);vboxsf.nix 则提供 mount.vboxsf 辅助程序(取自 linuxPackages.virtualboxGuestAdditions)。
NIX_PATH 不再默认包含 nixpkgs 路径
Nix 表达式搜索路径(NIX_PATH)默认不再包含 /etc/nixos/nixpkgs。可通过设置 nix.nixPath 覆盖。
Python 2.6 标记为 broken
Python 2.6 因上游停止安全更新而被标记为 broken,不再可用。
phpfpm 切换默认 PHP 版本
phpfpm 改用默认 PHP 版本(pkgs.php),不再使用 PHP 5.4(pkgs.php54)。
locate 不再索引 Nix store
locate 服务默认不再索引 Nix store,避免大量多版本软件包污染输出。如需索引,设置:
services.locate.includeStore = true;
注意:在现代仓库中该选项已被移除,改为推荐使用 services.locate.prunePaths(见 locate.nix 的 mkRemovedOptionModule 迁移提示),这是发布说明选项随版本演进的又一例证。
OpenBLAS 与 ATLAS 替换
OpenBLAS 更新至 0.2.14:新增 x86_64-darwin 平台支持,并启用动态架构检测——运行时自动选择微架构优化例程,无需本地重建 OpenBLAS 即可获得最优性能。OpenBLAS 已替代大多数使用优化 BLAS/LAPACK 的软件包中的 ATLAS。
TeX Live 2015
新打包的 TeX Live 2015 位于 pkgs.texlive,拆分成了 6500 个 Nix 包。注意安装过大包集合时存在已知问题(参考当时的 issue #9757)。官方计划在后续版本废弃并可能删除旧的 TeX 包。
模块系统变更:pkgs 模块参数限制
15.09 对模块求值方式做了一次严格化,任何使用模块参数(如 pkgs)访问库函数或定义 imports 属性的写法,都会在求值时陷入无限递归。排查方法:使用 –show-trace 命令行参数,读取错误信息上方的行:
$ nixos-rebuild build –show-trace
…
while evaluating the module argument `pkgs' in "/etc/nixos/my-module.nix":
infinite recursion encountered
迁移一:pkgs.lib 改为 lib 模块参数
任何 pkgs.lib 的使用都应替换为 lib,并把 lib 添加为模块参数。修改前:
{ config, pkgs, … }:
with pkgs.lib;
{
options = {
foo = mkOption {
# …
};
};
config = mkIf config.foo {
# …
};
}
修改后:
{
config,
pkgs,
lib,
…
}:
with lib;
{
options = {
foo = mkOption {
# option declaration
};
};
config = mkIf config.foo {
# option definition
};
}
迁移二:仅下载外部模块时用 import
仅当 pkgs 被用来下载其他项目以导入其模块时,才应替换为 (import <nixpkgs> {})。修改前:
{ config, pkgs, … }:
let
myProject = pkgs.fetchurl {
src = url;
sha256 = hash;
};
in
{
imports = [ "${myProject}/module.nix" ];
}
修改后:
{ config, pkgs, … }:
let
myProject = (import <nixpkgs> { }).fetchurl {
src = url;
sha256 = hash;
};
in
{
imports = [ "${myProject}/module.nix" ];
}
其他值得关注的改进
- nixos 与 nixpkgs channel 统一:现在可以直接 nix-env -iA nixos.bash,而无需再写 nix-env -iA nixos.pkgs.bash。
- buildEnv.env 可用:所有 Python 解释器上 buildEnv.env 现已可用于 nix-shell 互操作(现代实现见 passthrufun.nix,其 buildEnv 由 wrapper.nix 提供,withPackages 由 with-packages.nix 实现为对 buildEnv 的 override)。
总结与升级建议
NixOS 15.09 "Dingo" 是承前启后的重要版本:Haskell NG 将 Haskell 包管理彻底重构(其 ghcWithPackages 与 Stackage 支持沿用至今),Nix 1.10 引入的签名二进制缓存成为安全基线,system.autoUpgrade 与 system.stateVersion 则奠定了现代 NixOS 自动升级与版本兼容机制的基础。升级时务必按顺序核对:system.stateVersion 是否声明旧版本、cron 是否被显式启用、sshd 主机密钥类型、VirtualBox 选项新命名、模块中的 pkgs.lib 用法,以及所有 -chrootenv / 已改名包(bomi、electron、steam)的引用。发布说明中绝大多数选项名(如 services.openssh.moduliFile、services.locate.includeStore)在现代仓库中都能找到重命名或替换的迁移路径,这正是 NixOS 版本兼容机制长期有效的直接证据。
【免费下载链接】nixpkgs Nix Packages collection & NixOS 项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



