百科问答小站 logo
百科问答小站 font logo



如何评价 Nix ? 第1页

  

user avatar   dramforever 网友的相关建议: 
      

Nix 软件管理是 Nix 系列工具的基础。Nix 的一系列操作意在彻底解决软件之间依赖问题。或者说,解决提出问题的人(划掉)依赖本身。通过将软件作为一个 Nix 语言表达式的计算结果,而不是一个 build script 的副作用,Nix 很好的实现了这一目标。

Nix:宗旨就是锁版本

或者说,应该直接把版本这个东西忘掉。 在 Nix 里,每个软件是一个 Nix 语言里的表达式(软件的 derivation),包括这个软件的依赖、源码、build script。任何依赖如果没有保存在里面的话是用不了的。

包括依赖在内,有任何一点不一样的两个软件是不一样的,因为对应的 Nix 表达式是不一样的。

从每个 derivation 用 sha256 hash 算出一个编译结果的 id,所有的编译结果都会保存在 /nix/store/<id> 下。由此可知,在编译的时候,所有依赖都不能在 /usr/local/lib 下找,更不能在 PATH 下找,而要在 /nix/store 下写死了的一个目录里。

最极端又最普遍的例子:所有的 ELF 动态可执行文件的 dynamic linker 不是 /lib64/ld-linux-x86_64.so,是 /nix/store/...-glibc-2.26-131/lib/ld-linux-x86_64.so。此外,所有的 shell 脚本的 shebang 也不是 #!/bin/bash,而是 #!/nix/store/...-bash-.../bin/bash。

在编译一个 derivation 的时候,Nix 有一定的方式确定编译时的依赖,之后得到的编译结果再扫描一次得到运行时依赖。

一般的用户可能并不对自己编译软件感兴趣(除了 Gentoo)。对于 Nix 官方的软件库 nixpkgs,有一个 build server 编译所有软件,并按照 id 储存发布在一个 binary cache 服务器上。用户需要安装软件的时候,使用同一个 Nix 表达式计算出 derivation 对应的 id 之后,可以在 binary cache 上下载 /nix/store/<id> 的打包来代替编译。由于 id 一样的软件的 derivation 是相同的(sha256 够可以的了吧……),所以这样的代替是等效的。

nixpkgs:可能是世界上唯二的这么复杂的软件库

(因为还有个高仿 Guix)

Nix 的官方软件库叫 nixpkgs,还是比较神奇的一个设计。在 Nix 底层基于 derivation 的软件管理的基础上,nixpkgs 达到了很高的模块化和可配置性。

通过一些类似 OOP 的继承和 override 的方式,可以很方便的替换每个软件的具体的依赖和一部分选项。比如,nixpkgs.gcc 是使用 glibc 2.26 的,但是你可以用调用一个函数得到一个依赖 2.27 的 derivation。当然就需要重新编译了。这是因为其实 gcc 本身是一个返回 derivation 的函数,里面有一个参数就是其依赖 libc。gcc 返回的编译时的配置项里面用的是这个 libc 参数的 id。nixpkgs.gcc 是用 nixpkgs.glibc 作为参数调用这个函数的j结果,而你只要重新用 nixpkgs.glibc_2_27 调用就行了。

你还可以替换掉整个 nixpkgs 里某一个软件包。比如如果在 nixpkgs 里面用一个 overlay 将 nixpkgs.ghc 强行换成 8.6.1(nixpkgs.haskell.compiler.ghc861),那么所有本来依赖 ghc 的就都被换了。这一点可以参考 OOP 里面的继承和 override 理解。ghc 是 nixpkgs 的一个“方法”,你可以“继承”nixpkgs,并将 ghc 方法“override”掉,那么所有本来调用这个“方法”的别的“方法”的都会得到更新。

注意这两种操作都是所谓“纯函数式”的。这点很有必要 —— nixpkgs 里依赖于惰性求值来使得你安装一个软件不需要把整个 nixpkgs 里的所有 derivation 全都具体求出来,而且上述的 override 也依赖于这一点。

nix-shell:开发环境

除了软件的自动编译以外,Nix 还提供了开发环境的自动配置。nix-shell -A <pkg> 将会准备好 pkg 所需要的编译时依赖(大概类似 APT 的 build-depends),然后启动一个配置好这些依赖的 shell。因为所有软件分在 /nix/store/ 下的不同目录中,所以这些开发环境将互不干扰。此外使用 nixpkgs 提供的很多编程语言配置的辅助函数,也可以配置安装好了一些包的编译器环境的 nix-shell,功能上类似于 Python 的 virtualenv,或者 Haskell 的 Cabal sandbox。但是由于 Nix 可以管理全部依赖,包括一些所谓的“native”的库,所以具有更好的稳定性。例如,Nix 已经是 Haskell 的 reflex 库的推荐的环境配置方式。

用户环境配置和系统配置

nix-env 所做的操作可能更接近于传统意义上的“安装”软件。nix-env -iA <pkg> 会将 pkg 的可执行文件,manpages 等 soft link 到一个特定的目录下,并帮助配置 PATH 等,使得用户不需要在 shell 上还敲 /nix/store/ 的带有 id 的文件名运行程序。

NixOS 是一个基于 Nix 的操作系统发行版。在使用 Nix 管理所有软件的基础上,NixOS 还使用 Nix 语言进行系统配置,如分区挂载、用户、需要运行的服务及其设置项等。除了配置系统本身外,NixOS 还提供了从系统配置构建虚拟机或 container 的操作,方便进行测试。

所以结果呢?

我们得到了一个灵活的本质上基于源码发行版的同时,在里面实现了许多二进制发行版的便利。此外,Nix 及 nixpkgs 作为一种相对统一的灵活的软件配置格式,相当于还方便了源码发行版的配置。基于此,我们还在其上构建了一套独特的以声明式的方式进行系统配置的一套机制。

Nix 的“锁版本”还与现在流行的 Docker 等容器化技术在思想上有一定的统一性。如果只是分发软件的话,Nix 具有共享依赖、配置和运行的人力 overhead 小等优点,可以说完胜 Docker。如果需要容器所提供的 cgroup 和 namespace 之类的资源管理的话,也可以使用 nixpkgs 中的一些函数构建基于 Nix 的容器,或者在 Docker 容器里面使用 Nix,以得到 Nix 所提供的稳定性。

Nix 的一些问题

由于 Nix 的软件并没有常规意义上的覆盖安装,/nix/store 会占用比较大的空间。这点上类似 NodeJS 的 NPM。但是可以定期使用 nix-collect-garbage 来删除其中旧的软件版本或者不需要的文件。

此外,NixOS 为了实现其目的牺牲了一些对为现有通常 Linux 编译好的二进制程序的支持,使用上虽然有 patchelf 或者 chroot 之类的方式可以实现,但会有不便。

Nix 官方的 nixpkgs 的 binary cache 是 cache.nixos.org,在国内访问速度较慢,且暂时没有镜像。确实曾向一些镜像站提出过申请,但是由于技术上的原因暂时没有实现。(具体来说,Nix 的 binary cache 由于全部使用 hash 的 id 识别文件,其结构更适合对象存储,直接存入文件对文件系统压力过大。)

Nix 的稍微高级一点的配置需要写程序,要是苦手就费劲了。

Nix 的社区较小,导致比如 Nix 系列工具的文档很不全面。尤其是 nixpkgs 中,很多极其重要而常用的函数是没有文档的,为编写 Nix 程序带来一定阻力。

Nix 暂时缺少一个非统一管理的,类似 NPM 或者 PyPI 的可以随意上传的软件包库。

2020-03-26 更新:这些问题正在被逐渐解决:第一个国内的镜像站已经在运行,由 TUNA 提供[1];文档正在逐渐加上(在写了,在写了……),也有商业用户在推动 Nix 错误信息的优化[2];NUR[3]已经存在并运行一段时间,提供软件包和 NixOS module……因此如下推荐也有修改:

一些乱七八糟的推荐

NixOS:如果感兴趣,来试试吧,没准你会喜欢。如果打算弄一个 Linux 的虚拟机的话,可以试一下 NixOS,但是千万记得时常要 collect garbage。前几天我就 nix-collect-garbage -d,zerofree,VBoxManage --compact 捞回了 60GB 的硬盘空间 = =|

(2020-03-26 更新:删除开头的“暂时不是很推荐将 NixOS 作为日常个人使用的主系统”)

Nix:如果已经用了一个 Linux 的发行版的话可能用 Nix 装软件需求不大了,可以试一下的操作:

  • 可以试试使用 Nix 搭建开发环境,没准能解决几个“死活都装不上”的。
  • nixpkgs 里的很多编译器都考虑到了交叉编译的支持,可以试试看是不是稍微好装一点——有可能还有 binary 呢。正是因为 nixpkgs 里面的软件都是函数,使得其各种包括 build host target 的都可以作为配置项的参数统一管理,而不需要编译时手动去配置设置以及依赖项。
  • 可以考虑在项目里提供一个 default.nix 或者 shell.nix 的配置,让有兴趣的人更容易跑起开发环境来。
  • 可以试试在 CI 上使用 Nix 进行 build,依赖和 build 一体化管理,能方便一些。

我目前还没有尝试过使用 Nix 发布服务器软件及容器,所以暂时没有关于容器的具体内容,也没有说关于 NixOps 的事情。(那个东西真的有人用么 = =)所以希望有人或者以后可以补充……

参考

  1. ^ https://mirrors.tuna.tsinghua.edu.cn/help/nix/
  2. ^ https://discourse.nixos.org/t/proposal-for-improving-nix-error-messages/6305
  3. ^ https://github.com/nix-community/NUR



  

相关话题

  如何评价 Nix ? 
  如何评价 Nix ? 
  如何评价 Nix ? 
  如何评价 Nix ? 
  如何评价 Nix ? 
  如何评价 Nix ? 
  如何评价 Nix ? 
  如何评价 Nix ? 
  如何评价 Nix ? 
  如何评价 Nix ? 

前一个讨论
为什么RISC-V将超越ARM?
下一个讨论
如果把双缝干涉实验的电子换成离子、原子甚至是分子,会得出同样的实验结果吗?





© 2024-05-18 - tinynew.org. All Rights Reserved.
© 2024-05-18 - tinynew.org. 保留所有权利