Nix 中的构建与运行时依赖关系
Posted
技术标签:
【中文标题】Nix 中的构建与运行时依赖关系【英文标题】:Build versus Runtime Dependencies in Nix 【发布时间】:2016-04-18 13:56:57 【问题描述】:我才刚刚开始接触 Nix,如果我错过了文档中问题的答案,我深表歉意。
我想使用 Nix 来设置具有最少库和可执行文件集的安全生产机器。我不希望出现任何编译器或其他构建工具,因为这些可能是安全风险。
当我安装一些包时,它们似乎只依赖于最小的运行时依赖集。例如,如果我安装 apache-tomcat-8.0.23
,那么我会得到一个 Java 运行时 (JRE) 和包含 Tomcat 的预构建 JAR 文件。
另一方面,一些包似乎包含完整的构建工具链作为依赖项。再举一个基于 Java 的例子,当我安装 spark-1.4.0
时,Nix 会拉下包含编译器的 Java 开发工具包 (JDK),它还会拉下 Maven 构建工具等。
所以,我的问题如下:
-
Nix 包是否区分构建和运行时依赖项?
为什么有些包似乎依赖于构建工具,而另一些只需要运行时?这完全取决于包作者如何包装应用程序吗?
如果一个包包含我不想要的构建依赖项,作为操作员,除了为同一应用程序设计我自己的替代包之外,我还能做些什么吗?
非常感谢。
【问题讨论】:
【参考方案1】:运行时依赖项是构建时依赖项的子集,Nix 通过扫描生成的输出以查找每个构建时依赖项存储路径的哈希部分来自动确定。例如,如果您使用编译器 /nix/store/abcdef...-foo-1.20
构建一个包,那么 Nix 将扫描生成的输出中的所有文件以查找哈希位 abcdef...
。如果找到该散列,则假定输出以某种方式引用编译器,因此将其保留为运行时依赖项。但是,如果没有出现该哈希,则生成的输出没有对编译器的引用,因此无法在运行时访问它,因此 foo-1.20
被视为仅构建时依赖项。
某些软件包会记录其构建环境的大部分内容,用于提供信息/调试目的。例如,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实际上是如何做到这一点的?它是否适用于通过二进制文件中的exec
动态执行的路径?或者可能是生成的配置文件存储到另一个包的二进制文件的路径?
@CMCDragonkai,是的,似乎 nix 实际上扫描二进制文件以获取派生哈希。不幸的是,我找不到实际的代码,但这里有一些细节lethalman.blogspot.ru/2014/08/nix-pill-9-automatic-runtime.html
Source reference :)
我发现这种自动扫描不适用于 shell 脚本。因此,如果您的构建生成了一个 shell 脚本,您需要以某种方式包装以了解 PATH(如 makeWrapper
)或明确替换可执行调用。以上是关于Nix 中的构建与运行时依赖关系的主要内容,如果未能解决你的问题,请参考以下文章
npm:依赖关系vs devDependencies与捆绑的依赖关系