Nix (软件包管理器)
Nix 是一个软件包管理器和构建系统,它解析由 Nix 表达式语言 (惰性求值的纯函数式语言) 指定的可复现的构建指令。Nix 表达式是纯函数[1],它接受依赖作为参数,并生成一个 derivation,用于指定该软件包的可复现的构建环境。Nix 把构建的结果存储在由完整依赖树的哈希值指定的唯一地址中,从而创建了一个不可变的包存储 (即 nix store),使得原子升级、回滚、以及同时安装同一软件包的不同版本成为可能,从根本上消除了依赖地狱。
用法
安装
在 NixOS 上,Nix 已经自动安装好了。
如果你想在其他 Linux 发行版或在 macOS 上使用 Nix, 你可以按照 Nix 手册的安装章节来安装 Nix。
Nix 命令
Nix 命令在 Nix 参考手册中有详细记录:主要命令,工具命令和实验性命令。在 2.0 版本(于 2018 年 2 月发布)之前,命令有所不同。
配置
在 NixOS 上, Nix 可以通过 nix
选项进行配置。
独立的 Nix 通过 nix.conf
进行配置(其通常位于 /etc/nix/
)。可用选项的详细说明可在 Nix 参考手册中找到.
你也可以使用 Home Manager 配置 Nix,它为单用户管理声明式环境。对于系统范围的配置,可以在 Linux 上使用 System Manager,在 macOS 上使用 nix-darwin。
内部组成
Nix store
由 Nix 构建的软件包会被放置在只读的 Nix store 中,通常位于 /nix/store
。每个软件包都会被赋予一个唯一的地址,该地址由加密哈希值、软件包名称和版本组成,例如 /nix/store/nawl092prjblbhvv16kxxbk6j9gkgcqm-git-2.14.1
。这些前缀对构建过程中的所有输入进行哈希,包括源文件、完整的依赖树、编译器参数等。这使得 Nix 能够同时安装同一软件包的不同版本,甚至是同一版本的不同构建(例如使用不同编译器构建的变体)。在添加、移除或更新软件包时,存储中的内容不会被删除;相反,profiles 中指向这些软件包的符号链接会被添加、移除或更改。
清理 Nix store
有关清理 Nix store 的信息,请参阅 NixOS 手册:章节 - 清理 Nix 存储。
Nix store 损坏
有关修复 Nix store 损坏的信息,请参阅 NixOS 手册:章节 - Nix store 损坏。
有效的 Nix store 名称
- Main article: Valid Nix store path names
Profiles
为了构建一个一致的用户和系统环境,Nix 会将 Nix store 中的条目符号连结到 profiles 中。这是 Nix 实现回滚的前端:由于 store 是不可变的且保留先前版本的 profile,将系统还原到先前的状态只需简单地将符号连结更改为先前的 profile。更精确地说,Nix 将二进制档符号连结到 Nix store 中代表用户环境的条目中。这些用户环境随后被符号连结到储存在 /nix/var/nix/profiles
中被标注的 profile,而它们则进一步符号连结到使用者的 ~/.nix-profile
。
沙盒
当启用沙盒构建时,Nix 会为每个构建过程设置一个隔离的环境。这样可以去除构建环境中额外的隐藏依赖,以提高可复现性。这包括在构建过程中禁止访问 fetch*
函数之外的网络,以及禁止访问 Nix store 之外的文件。根据操作系统的不同,对其他资源的访问也会被阻止(例如在 Linux 上进程间通信会被隔离);详细信息请参阅 Nix 手册中的 nix.conf 章节。
沙盒在 Linux 上预设是开启的,在 macOS 上则否。
在 Nixpkgs 的提取请求 (pull request) 中,请开启沙盒模式进行测试(请见提取请求模版中的 Tested using sandboxing
),因为在 官方 Hydra 构建中,沙盒会被使用。
要为 Nix 配置沙盒,请在 /etc/nix/nix.conf
中设置 sandbox = true
;要为 NixOS 配置沙盒,请在 configuration.nix
中设置 nix.useSandbox = true;
。自 NixOS 17.09 起,nix.useSandbox
选项默认为 true
。
可选的解释器
目前正在进行一项计划,从零开始使用 Rust 重新实作 Nix。
有一个社群领导的 Nix 2.18 分支叫做 Lix,专注于正确性、可用性和成长性。同时它还为 Nix 部分组件加入 Rust 端口,但不像从零开始重写的 Tvix。
早期的尝试可以在 riir-nix 找到。
备注
- ↑ 值在计算过程中不会改变。当函数的输入不变时,函数总是输出相同的结果。