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 构建工具等等
那么,我的问题如下:
- Nix 包是否区分构建和运行时依赖项?
- 为什么有些包似乎依赖于构建工具而其他包只需要运行时?这完全取决于包作者如何包装应用程序吗?
- 如果一个包包含我不想要的构建依赖项,作为操作员,除了为同一应用程序设计我自己的替代包之外,我还能做些什么吗?
非常感谢。
运行时依赖项是 build-time 依赖项的子集,Nix 通过扫描每个 build-time 依赖项存储路径的哈希部分生成的输出来自动确定。例如,如果您使用编译器 /nix/store/abcdef...-foo-1.20
构建包,则 Nix 将扫描生成的输出中的所有文件以查找散列位 abcdef...
。如果找到该散列,则假定输出以某种方式引用编译器,因此它会作为运行时依赖项保留。但是,如果没有出现该散列,则生成的输出没有对编译器的引用,因此无法在运行时访问它,因此 foo-1.20
被视为 build-time-only 依赖项。
一些软件包出于 informational/debugging 目的记录了大部分构建环境。例如,Perl 存储了有关用于编译它的工具的所有细节,因此所有这些存储路径最终都被视为运行时依赖项,尽管 Perl 在运行时实际上并不需要它们,但 Nix 不知道:它只知道 Perl 存储路径 references 那些工具。现在,Nixpkgs 维护者通常会努力清理它,即通过修剪包含安装中所有这些存储路径的日志文件等,但可以肯定的是,数据库中仍有大量软件包尚未优化到此为止了。
假设您想要编译不依赖于 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
我才刚刚开始接触 Nix,如果我在文档中错过了问题的答案,我深表歉意。
我想使用 Nix 使用最少的库和可执行文件集来设置安全的生产机器。我不希望存在任何编译器或其他构建工具,因为它们可能存在安全风险。
当我安装一些包时,它们似乎只依赖于最小的运行时依赖集。例如,如果我安装 apache-tomcat-8.0.23
,那么我会得到一个 Java 运行时 (JRE) 和包含 Tomcat.
另一方面,一些软件包似乎包含完整的构建工具链作为依赖项。举另一个基于 Java 的例子,当我安装 spark-1.4.0
Nix 时,它会拉下包含编译器的 Java 开发工具包 (JDK),它还会拉取 Maven 构建工具等等
那么,我的问题如下:
- Nix 包是否区分构建和运行时依赖项?
- 为什么有些包似乎依赖于构建工具而其他包只需要运行时?这完全取决于包作者如何包装应用程序吗?
- 如果一个包包含我不想要的构建依赖项,作为操作员,除了为同一应用程序设计我自己的替代包之外,我还能做些什么吗?
非常感谢。
运行时依赖项是 build-time 依赖项的子集,Nix 通过扫描每个 build-time 依赖项存储路径的哈希部分生成的输出来自动确定。例如,如果您使用编译器
/nix/store/abcdef...-foo-1.20
构建包,则 Nix 将扫描生成的输出中的所有文件以查找散列位abcdef...
。如果找到该散列,则假定输出以某种方式引用编译器,因此它会作为运行时依赖项保留。但是,如果没有出现该散列,则生成的输出没有对编译器的引用,因此无法在运行时访问它,因此foo-1.20
被视为 build-time-only 依赖项。一些软件包出于 informational/debugging 目的记录了大部分构建环境。例如,Perl 存储了有关用于编译它的工具的所有细节,因此所有这些存储路径最终都被视为运行时依赖项,尽管 Perl 在运行时实际上并不需要它们,但 Nix 不知道:它只知道 Perl 存储路径 references 那些工具。现在,Nixpkgs 维护者通常会努力清理它,即通过修剪包含安装中所有这些存储路径的日志文件等,但可以肯定的是,数据库中仍有大量软件包尚未优化到此为止了。
假设您想要编译不依赖于 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