文章简介
约 1546 字大约 5 分钟
LinuxNixFlake
2025-01-29
Linux的发行版浩如烟海,其本质无非是内核搭配一些基础工具,方便用户的使用,随着用户需求的不断复杂化,包管理器功能也逐渐被划归到发行版的功能之中,到最后,内核和基础工具也被划归到包管理器的管理范畴。可以说,包管理器就是发行版的基石,其管理着系统中几乎所有的软件(包括内核甚至是Bootloader),而包管理器的不同也作为划分发行版谱系的重要依据之一。
大部分Linux新人接触到的都是Debian
系,它们是基于apt
包管理器的发行版,这个家族的成员有Debian
、Ubuntu
、Deepin
等等;比较特殊的还有Arch
系,它们是基于pacman
包管理器的发行版,典型成员有Archlinux
和Manjaro
。
而我们要介绍的NixOS
是其中的异类,它基于nix
包管理器,是一个声明式的包管理器。
必须要澄清的是,叫做
Debain
系的原因是这些发行版都衍生自Debain
,而基于apt
仅仅是其判断依据,Arch
系同理。
所以,nix
有什么不一样?
在Arch
系中,我们使用pacman
在终端中安装软件,比如:
pacman -S clang
一旦该命令成功,该软件就会永远留存在你的系统中,除非我们手动卸载该包(pacman -Rs
),这种方式符合直觉,简单易懂,但存在以下缺点:
- 配置分散: 虽然大部分软件都遵守LFS规范,但它们的配置文件往往处于不同的位置,使用不同的配置语言,这导致了用户很难管理系统配置。
- 依赖管理混乱: 虽然我们能通过命令获取当前系统中所有的软件和版本,但我们往往没有有效的手段确保这种依赖关系是确定的(因为我们使用的软件源几乎不可能一致),这很可能会导致某开发环境在当前系统中可以运行,但到了另一个系统上就失效了。
- 难以管理外部软件: 如果软件源不满足我们的需求,我们很有可能需要寻求手动安装,一般的发行版并没有对这种软件进行约束,在其编译安装过程中,发行版完全不知情,但其安装结果很有可能改变了某些文件布局,导致某些软件无法正常运行,甚至整个系统崩溃。
nix
提供了一种全新的方式,它在实际的LFS路径和软件包之间加入了一层中间层(在NixOS
中通常位于/nix/store/
),安装软件会在该目录中新建一个由哈希和软件包名组成的路径(来唯一表示该软件包),这个路径是只读的,只有nix
相关命令可以修改该目录。在系统启动时,nix
会将这个目录中安装的所有软件映射到真正的LFS目录中(一般是/run/current-system/
)。
为了适配这套软件安装逻辑,nix
还需要一套配置来描述整个系统,用来最终导出系统需要的所有软件包和其配置,我们称之为nix
配置文件(一般位于/etc/nixos
),每次我们需要安装软件或者修改软件时,我们需要将内容添加到配置文件中,然后重新计算整个配置文件,生成新的系统配置(我们称之为generation
或者profile
)。
举个例子,我们的配置文件中如果有如下内容:
{ pkgs, ... }:{
environment.systemPackages = [ pkgs.clang_19 ];
}
在重新生成系统配置之后,我们可以在上述目录中找到:
/nix/store/0jf7aq1bhi5609mylnas50qrsiclbp34-clang-wrapper-19.1.4/
这里包含了clang
这个软件的构建结果,同时,我们也可以在上述目录中找到:
/run/current-system/sw/usr/bin/clang
对于上面的所有内容,用户只允许更改配置文件,而后面生成的路径下面的所有内容都是只读的,这极大限制了用户的操作空间,限制系统中所有的软件都只应通过配置文件注入,当然,nix
提供了大量的方式增强配置文件的能力,在一般发行版中能做到的事,在nix
中几乎都能做到。
上面提到的哈希是笔者在自己的
/nix/store
中找到的,不代表所有的clang_19
均为该哈希。
解决软件源的问题
早年的nix
并没有解决软件源的问题,直到flake
的出现,flake
是nix
的项目管理器,它通过将软件源参数化来控制软件源一致性。
使用过Cargo
等现代项目管理器的读者想必很熟悉.lock
文件,它通过哈希控制项目中每个依赖的在不同的环境中的一致性,flake
也使用了这种方式,它将系统配置转换为一个flake
项目,将软件源作为它的一个依赖传入,通过flake.lock
确定该源在所有环境中的一致性。
本教程着重介绍flake
特性,不会涉及过多传统nix
的操作。
尽管
flake
现在仍然是一个实验特性,但鉴于其目前的使用情况,其稳定性已经得到了保证。
迁移到nix
的注意事项
迁移到nix
是非常困难的,因为其几乎不支持任何其他发行版通用的约定,例如LFS路径等,这会导致:
nix
构建的二进制文件和其他发行版不兼容(可以通过patchelf解决该问题)- 外部二进制文件很难在
NixOS
中运行(可以通过手动打包或者nix-ld
解决) - 开发环境配置逻辑和其他发行版完全不同
本教程的目的
本教材旨在处理上述提到的注意事项,带领读者一步步接受nix
哲学,并体会其中的便利性。