Nix 中的构建与运行时依赖关系

Build versus Runtime Dependencies in Nix

我才刚刚开始接触 Nix,如果我在文档中错过了问题的答案,我深表歉意。

我想使用 Nix 使用最少的库和可执行文件集来设置安全的生产机器。我不希望存在任何编译器或其他构建工具,因为它们可能存在安全风险。

当我安装一些包时,它们似乎只依赖于最小的运行时依赖集。例如,如果我安装 apache-tomcat-8.0.23,那么我会得到一个 Java 运行时 (JRE) 和包含 Tomcat.

的预构建 JAR 文件

另一方面,一些软件包似乎包含完整的构建工具链作为依赖项。举另一个基于 Java 的例子,当我安装 spark-1.4.0 Nix 时,它会拉下包含编译器的 Java 开发工具包 (JDK),它还会拉取 Maven 构建工具等等

那么,我的问题如下:

  1. Nix 包是否区分构建和运行时依赖项?
  2. 为什么有些包似乎依赖于构建工具而其他包只需要运行时?这完全取决于包作者如何包装应用程序吗?
  3. 如果一个包包含我不想要的构建依赖项,作为操作员,除了为同一应用程序设计我自己的替代包之外,我还能做些什么吗?

非常感谢。

  1. 运行时依赖项是 build-time 依赖项的子集,Nix 通过扫描每个 build-time 依赖项存储路径的哈希部分生成的输出来自动确定。例如,如果您使用编译器 /nix/store/abcdef...-foo-1.20 构建包,则 Nix 将扫描生成的输出中的所有文件以查找散列位 abcdef...。如果找到该散列,则假定输出以某种方式引用编译器,因此它会作为运行时依赖项保留。但是,如果没有出现该散列,则生成的输出没有对编译器的引用,因此无法在运行时访问它,因此 foo-1.20 被视为 build-time-only 依赖项。

  2. 一些软件包出于 informational/debugging 目的记录了大部分构建环境。例如,Perl 存储了有关用于编译它的工具的所有细节,因此所有这些存储路径最终都被视为运行时依赖项,尽管 Perl 在运行时实际上并不需要它们,但 Nix 不知道:它只知道 Perl 存储路径 references 那些工具。现在,Nixpkgs 维护者通常会努力清理它,即通过修剪包含安装中所有这些存储路径的日志文件等,但可以肯定的是,数据库中仍有大量软件包尚未优化到此为止了。

  3. 假设您想要编译不依赖于 PAM 的 openssh 版本。然后您可以通过覆盖从表达式中删除构建输入,即您将通常传递给 openssh 构建函数的 pam 参数替换为 null。为此,请将以下文件存储在 ~/.nixpkgs/config.nix

    {
      packageOverrides = super: let self = super.pkgs; in {
        openssh-without-pam = super.openssh.override {
          pam = null;
        };
      };
    }
    

    现在通过 运行 安装该软件包:

    $ nix-env -f "<nixpkgs>" -iA openssh-without-pam