【发布时间】:2021-07-17 17:21:17
【问题描述】:
在查看Nixpkgs repo 中的包时遇到patchShebangs 命令,并看到它在standard environment 的通用构建器的various phases 中使用,但不确定它的用途或为什么需要它首先。
【问题讨论】:
在查看Nixpkgs repo 中的包时遇到patchShebangs 命令,并看到它在standard environment 的通用构建器的various phases 中使用,但不确定它的用途或为什么需要它首先。
【问题讨论】:
简而言之:在 Nix 构建期间使用的 shell 脚本不能开箱即用,因为 Nix 会清除环境,因此解释器指令 (shebang) 在脚本的第一行确定用于评估的程序脚本正文,将找不到它。 patchShebangs 在 Nix 商店中查找解释器,并修改脚本 shebang。
Nixpkgs manual在描述Nixpkgs standard environment的the phases of the generic builder时间接提到patchShebangs,说明fixup phase在某一点上
将 shell 脚本的解释器路径重写为在
PATH中找到的路径。例如,/usr/bin/perl将被重写为在PATH中找到的/nix/store/some-perl/bin/perl。 ->
请务必注意(解释为 @jonringer's comment),“patchShebangs 命令仅在您获取 $stdenv/setup 设置挂钩的情况下在构建期间可用" (更多内容见下文) "由stdenv's (Nixpkgs standard environment's) 默认构建器提供(使用stdenv.mkDerivation 时默认得到这个),这就是为什么起点几乎所有 nix 表达式都是import <nixpkgs> {}, stdenv.mkDerivation,或类似的东西。"
patchShebangs 定义在哪里Nixpkgs repo 中的文件patch-shebangs.sh(也记录在6.7.4. patch-shebangs.sh)定义了patchShebangs function,而patchShebangs function 又用于实现patchShebangsAuto,setup hook 在@ 期间是registered to run 987654336@.
根据patch-shebangs.sh顶部的评论:
# This setup hook causes the fixup phase to rewrite all script
# interpreter file names (`#! /path') to paths found in $PATH. E.g.,
# /bin/sh will be rewritten to /nix/store/<hash>-some-bash/bin/sh.
# /usr/bin/env gets special treatment so that ".../bin/env python" is
# rewritten to /nix/store/<hash>/bin/python. Interpreters that are
# already in the store are left untouched.
# A script file must be marked as executable, otherwise it will not be
# considered.
重要提示:上述“脚本文件必须标记为可执行文件,否则将不被视为”的标准是重要的。
shell 脚本中以#! 开头的行称为shebang(以及其他),它是执行shell 的解释器指令,用于解释使用什么程序来破译下面的文本; #! has to consitute an absolute path that points to this executable 之后的字符。例如,#!/usr/bin/python3 将期望在那里找到python3 程序来执行用 Python 编程语言编写的 shell 脚本主体中的命令。
在包构建阶段使用 shell 脚本会出现问题,因为
当 Nix 运行 builder, 时,它最初会完全清除环境(派生中声明的属性除外)。例如,
PATH变量为空。这样做是为了防止在构建过程中使用未声明的输入。例如,如果 PATH 包含/usr/bin,那么您可能会不小心使用/usr/bin/gcc。 ->
上面的引用是from the Nix manual,但作为示例显示的构建器使用$stdenv/setup - 一个为构建过程设置原始沙箱环境的shell脚本,取消设置大多数(全部?)环境变量来自调用 shell 和 only including a small number of utilities。 (这样做是为了尽可能使构建可重现。)1
stdenv.mkDerivation 与the generic builder 一起使用时通常会隐式调用$stdenv/setup(即,当builder 属性未声明时)但one can write their own builders and invoke it explicitly during the build process。
提示:This answer 显示了一种查找特定 Nix 函数定义位置的方法(尽管 it is not infallible)。
作为推论,shebang 指令指向的程序不会在这些位置(或无法从沙盒访问),但它们实际上在(或将在)Nix store 中,因此路径将需要重新指向他们在那里的位置。
注意:generic builder 从派生的 输入 填充 PATH,因此必须确保将这些作为依赖项包含在内。
如上所述,每当构建包时,patchShebangsAuto setup hook 在fixup phase 期间自动调用patchShebangs - 除非通过设置dontPatchShebangs variable(或dontFixup变量)(参见Nixpkgs manual 中的Variables controlling the fixup phase)。
提醒自己:6.4 Bash Conditional Expressions.
3.1.0 patchShebangs 在自动调用时使用什么脚本?
通常在包安装的脚本上(例如$out/bin)。
还是 Nixpkgs 标准库默认提供的?我认为这些必须足够通用才能在不同的平台上运行,以便 (1) 构建模板,以及 (2) 最后修补脚本 shebangs。 (@jtojnar confirmed this conjecture,但是这部分需要参考,因此是小案例。)
3.1.1 如何使用控制构建阶段的变量?
将它传递给mkDerivation,就像控制构建器的任何其他变量一样。
stdenv.mkDerivation {
#...
dontPatchShebangs = true;
#...
}
历史记录:最初,patchShebangs 不能在外部调用,但it was later extracted 使其功能也可在其他build phases 中重复使用。
再次,来自the implementation 中的 cmets:
# Run patch shebangs on a directory or file.
# Can take multiple paths as arguments.
# patchShebangs [--build | --host] PATH...
# Flags:
# --build : Lookup commands available at build-time
# --host : Lookup commands available at runtime
# Example use cases,
# $ patchShebangs --host /nix/store/...-hello-1.0/bin
# $ patchShebangs --build configure
它需要在构建期间直接执行的脚本(包括 shell 脚本)上运行。这些可能是
来自网络的具体例子:
这正是显式
patchShebangs调用的用例。 Meson 构建系统期望运行src/shared/generate-syscall-list.py,所以它调用它。但这失败了,因为构建沙箱中不存在/usr/bin/env。而且它只会让人感到困惑,因为 kernel/libc/something else 报告该脚本不存在,即使它是来自 shebang 的解释器不存在。
[1]:待办事项:详细了解沙盒的准确构建方式以及禁止和允许的内容。 Quoting @jtojnar举个例子:
/usr/bin/env,沙盒中也不可用。 (为方便起见,NixOS 仅在用户空间中提供了该功能,但 does not carry over to Nix sandbox.。
[2]: @jtojnar's comment: "是的,你不需要显式地将它用于仅在运行时执行的脚本,因为它们将由隐式调用处理。"
此线程中的所有链接(希望)都已保存到Internet Archive。 (线程的配乐是this gem。)
【讨论】: