- 包管理器
- 操作系统
【免费下载链接】nixpkgs
Nix Packages collection & NixOS
本指南基于 NixOS 手册"Package Management"章节,系统讲解 NixOS 添加软件的两种包管理风格:以configuration.nix为载体的声明式管理,以及以nix-env命令为核心的临时(Ad Hoc)管理。读完本文,你将掌握environment.systemPackages选项的底层原理、nix-env的安装/升级/卸载/回滚操作,以及两者的适用场景与本质区别,并能在 Nixpkgs 仓库中追踪到对应实现源码。
NixOS 的两种软件包管理风格
在 NixOS 中,为系统添加软件包有两种截然不同的方式(见 package-mgmt.chapter.md):
- 声明式(Declarative):在
configuration.nix中声明你想要的软件包。每次执行nixos-rebuild,NixOS 都会确保你获得一组与配置规范完全一致的、可复现的二进制软件集。 - 临时(Ad hoc):通过
nix-env命令安装、升级和卸载软件包。这种方式允许混合使用不同 Nixpkgs 版本的软件包,而且它是非 root 用户唯一可用的方式。
两种方式对应手册中的两个独立小节:声明式软件包管理 与 临时软件包管理。下面分别深入讲解。
声明式软件包管理:一切由 configuration.nix 决定
声明式管理的核心是配置选项environment.systemPackages。例如,在/etc/nixos/configuration.nix中加入下面一行即可启用 Mozilla Thunderbird 邮件客户端:
{ environment.systemPackages = [ pkgs.thunderbird ]; }其效果是:每当你运行nixos-rebuild switch,Thunderbird 包就会作为系统构建的一部分被编译或下载,并进入系统环境。要"卸载"某个包,只需把它从environment.systemPackages中移除,然后再次执行nixos-rebuild switch——系统会自动切换到不含该包的下一代配置。
底层实现:system-path 与 /run/current-system/sw
从源码层面看,该选项定义在 nixos/modules/config/system-path.nix:
environment.systemPackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = [ ]; example = lib.literalExpression "[ pkgs.firefox pkgs.thunderbird ]"; description = '' The set of packages that appear in /run/current-system/sw. These packages are automatically available to all users, and are automatically updated every time you rebuild the system configuration. ''; };关键信息有两点:
- 该选项类型是"package 列表",默认值为空,示例写法
[ pkgs.firefox pkgs.thunderbird ]与手册中的用法完全一致。 - 所有列入该选项的包最终都会出现在
/run/current-system/sw目录,对所有用户自动可用,并且在每次系统重建时自动更新——这正是它与"默认 profile 安装"(/nix/var/nix/profiles/default)的本质区别。
在配置装配阶段(system-path.nix),systemPackages还会自动叠加内置的corePackages与defaultPackages:
environment.systemPackages = config.environment.corePackages ++ config.environment.defaultPackages;随后整个包集被交给pkgs.buildEnv构建成system.path(即/run/current-system/sw),并按 pathsToLink 的默认设置将/bin、/sbin、/etc/xdg、/lib等目录软链接进系统环境(见 system-path.nix)。这就是"重启后软件对所有人可见"的实现机制。
注意事项:并非所有包都能只靠 systemPackages 工作
手册特别提醒:某些软件包还需要额外的全局配置,例如 D-Bus 服务或 systemd 服务的注册。仅仅把它们加入environment.systemPackages可能不够。建议先在 NixOS 模块选项列表 中查一下该软件是否已存在对应的 NixOS 模块(如programs.firefox、services.*等)。这类带模块的包通常应该用模块启用,以获得完整的集成。
查询可用软件包
你可以用nix-env列出 Nixpkgs 中所有可用软件包及其描述:
$ nix-env -qaP '*' --description nixos.firefox firefox-23.0 Mozilla Firefox - the browser, reloaded ...输出中第一列是属性名(attribute name),例如nixos.thunderbird。请注意前缀语义:
nixos前缀表示从nixos渠道获取该包,它只在命令行工具中有效;- 在声明式配置(
configuration.nix)中,必须改用pkgs前缀(pkgs是配置文件中的内置变量),写成pkgs.thunderbird。
临时(Ad Hoc)软件包管理:用 nix-env 即时操作
对于不需要声明进配置、只想临时使用的软件,nix-env是更灵活的手段。它也非 root 用户唯一可用的安装方式。
安装软件包
安装 Mozilla Thunderbird:
$ nix-env -iA nixos.thunderbird这里的关键在于-A标志:
- 带
-A时,按属性名(attribute name)精确指定软件包; - 不带
-A时,则按包名(package name,例如thunderbird)在所有 Nix 包中做匹配。这种方式更慢(需要对全部包做匹配),而且存在歧义风险——若有多个同名包会无法确定装哪个。
安装位置与可见性
nix-env将软件装进 Nix profile,安装位置取决于执行用户身份:
| 执行身份 | 安装位置 | 可见性 |
|---|---|---|
| root | /nix/var/nix/profiles/default | 系统所有用户可见 |
| 普通用户 | /nix/var/nix/profiles/per-user/<用户名>/profile | 仅该用户可见 |
升级软件包
临时安装的包来自 NixOS 渠道。典型的升级流程是先把 NixOS 渠道更新到最新:
$ nix-channel --update nixos然后重新执行nix-env -i(重新安装目标包)。此过程不会影响 profile 中的其他包——这是与声明式管理的决定性差异:声明式下执行nixos-rebuild switch会把所有包都同步到 NixOS 渠道中的当前版本,而nix-env是"各装各的"。
若想一次性升级 profile 中所有有新版可用的包,可执行:
$ nix-env -u '*'卸载与回滚
卸载某个包用-e标志(按包名指定):
$ nix-env -e thunderbird最后,如果某次nix-env操作结果不理想,可以一键回滚:
$ nix-env --rollbacknix-env还支持更多标志,完整说明见nix-env(1)手册页。由于 Nix 的 store 天然保留历史世代(generations),回滚几乎是即时且无损的。
软件包不够用怎么办:添加自定义软件包
当 Nixpkgs 中没有你需要的软件时,手册提供了两条出路(详见 添加自定义软件包):用 Nix 打包,或使用上游预编译二进制。由于 NixOS 的文件系统布局与主流发行版差异较大,从源码构建往往比使用预编译可执行文件更容易成功。
在 Nixpkgs 树内打包(in-tree)
克隆 Nixpkgs 仓库,把新包加入自己的克隆,可选地向主仓库提交补丁或 Pull Request。完成后把它加入environment.systemPackages:
{ environment.systemPackages = [ pkgs.my-package ]; }重建时用-I指定自己的 Nixpkgs 树:
# nixos-rebuild switch -I nixpkgs=/path/to/my/nixpkgs在 configuration.nix 中直接打包(out-of-tree)
也可以直接在configuration.nix里用stdenv.mkDerivation定义构建,例如构建 GNU Hello:
{ environment.systemPackages = let my-hello = pkgs.stdenv.mkDerivation (finalAttrs: { pname = "hello"; version = "2.8"; src = pkgs.fetchurl { url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz"; hash = "sha256-5rd/gffPfa761Kn1tl3myunD8TuM+66oy1O7XqVGDXM="; }; }); in [ my-hello ]; }更优雅的做法是把包定义抽到独立文件(如my-hello.nix),再通过callPackage引入:
{ environment.systemPackages = [ (pkgs.callPackage ./my-hello.nix { }) ]; }其中my-hello.nix的内容为:
{ stdenv, fetchurl }: # declare dependencies as arguments stdenv.mkDerivation (finalAttrs: { pname = "hello"; version = "2.8"; src = fetchurl { url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz"; hash = "sha256-5rd/gffPfa761Kn1tl3myunD8TuM+66oy1O7XqVGDXM="; }; })这样还可以在不重建整个系统的情况下单独测试该包:
$ nix-build -E 'with import <nixpkgs> { }; callPackage ./my-hello.nix { }' $ ./result/bin/hello Hello, world!预编译可执行文件的两个例外
大多数预编译可执行文件无法直接在 NixOS 上运行,但有两类例外:Flatpak 与 AppImage。AppImage 在 NixOS 上可以"原样"运行,前提是先启用支持:
{ programs.appimage.enable = true; programs.appimage.binfmt = true; }之后可直接运行foo.appimage,或用appimage-run foo.appimage。若缺少共享库,可通过覆盖补充:
{ programs.appimage.package = pkgs.appimage-run.override { extraPkgs = pkgs: [ # missing libraries here, e.g.: `pkgs.libepoxy` ]; }; }其他预编译程序则需用autoPatchelfHook或buildFHSEnv等工具配合 Nix 打包才能运行,过程复杂,往往不如直接源码构建。
小结:如何选择包管理方式
| 维度 | 声明式(environment.systemPackages) | 临时(nix-env) |
|---|---|---|
| 配置载体 | /etc/nixos/configuration.nix | 命令行 |
| 生效方式 | nixos-rebuild switch | 即时生效 |
| 版本一致性 | 每次重建时整组同步到渠道当前版本 | 各包独立,可混用不同版本 |
| 可见性 | 所有用户可见(装入/run/current-system/sw) | root 装全局,普通用户仅自己可见 |
| 非 root 用户 | 不可用 | 唯一选择 |
| 卸载/回滚 | 从配置中移除后重建 | nix-env -e/nix-env --rollback |
两种方式各有用武之地:追求可复现、可审计的系统配置,优先声明式;临时试用、非 root 环境、希望混用不同版本,则使用nix-env。掌握二者并结合 添加自定义软件包 与 自定义软件包 中的技巧,即可在 NixOS 上从容应对绝大多数软件安装场景。
- 包管理器
- 操作系统
【免费下载链接】nixpkgs
Nix Packages collection & NixOS
相关推荐
NixOS 容器管理完全指南:命令式与声明式两种方案实战
NixOS 容器管理完全指南:命令式与声明式两种方案实战 NixOS 提供了轻量级的虚拟化方案——容器(Containers),让宿主系统与容器共享 Nix s
包管理器操作系统NixOS 临时包管理(Ad-Hoc)实战指南:使用 nix-env 安装、升级与回滚软件包
NixOS 临时包管理(Ad Hoc)实战指南:使用 nix env 安装、升级与回滚软件包 导读 在 NixOS 中,软件包管理存在两种并行的风格:声明式(d
包管理器操作系统NixOS 声明式包管理实战:environment.systemPackages 选项与系统路径实现的深度解析
NixOS 声明式包管理实战:environment.systemPackages 选项与系统路径实现的深度解析 在 NixOS 中,管理"系统装了哪些软件"有
包管理器操作系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考