0

在查看Nixpkgs repo中的包时遇到了该patchShebangs命令,并看到它在标准环境的通用构建器的各个阶段中使用,但不确定它的用途或首先需要它的原因。

4

1 回答 1

1

简而言之:在 Nix 构建期间使用的 shell 脚本不能开箱即用,因为 Nix 清除了环境,因此脚本第一行的解释器指令 (shebang) 确定了用于评估脚本主体的程序,不会找到。patchShebangs在 Nix 商店中查找解释器,并修改脚本 shebang。


0. 简介

patchShebangsNixpkgs 手册中在描述Nixpkgs 标准环境的通用构建器的阶段时间接提及,指出修复阶段在某一点

将 shell 脚本的解释器路径重写为PATH. 例如,/usr/bin/perl将被重写为/nix/store/some-perl/bin/perlPATH. ->

重要的是要注意(解释@jonringer 的评论),“patchShebangs命令仅在您获取$stdenv/setupsetup hook时才在构建期间可用”(更多内容见下文)“stdenvNixpkgs 标准环境)默认构建器提供(使用时默认会得到这个stdenv.mkDerivation),这就是为什么几乎所有 nix 表达式的起点都是import <nixpkgs> {}, stdenv.mkDerivation,或类似的东西。

patchShebangs1.定义在哪里

Nixpkgs 存储库patch-shebangs.sh中的文件(也记录在6.7.4.patch-shebangs.sh 中)定义了该函数,该函数又用于实现注册修复阶段运行的设置挂钩patchShebangspatchShebangsAuto

2. 为什么在构建 Nix 包时需要 shebang 重写?

根据顶部的评论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 的解释器指令,用于解释使用什么程序来破译下面的文本;后面的字符#! 必须构成指向该可执行文件的绝对路径。例如,#!/usr/bin/python3将期望在python3那里找到程序以执行用 Python 编程语言编写的 shell 脚本主体中的命令。

在包构建阶段使用 shell 脚本会变得有问题,因为

当 Nix 运行 builder时,它最初会完全清除环境(在派生中声明的属性除外)。例如,PATH变量为空。这样做是为了防止在构建过程中使用未声明的输入。例如,如果包含 PATH /usr/bin,那么您可能会不小心使用/usr/bin/gcc. ->

上面的引用来自 Nix 手册,但作为示例显示的构建器使用$stdenv/setup- 一个 shell 脚本,为构建过程设置原始沙箱环境,从调用 shell 中取消设置大多数(全部?)环境变量,并且只包括少数实用程序。(这样做是为了使构建尽可能可重现。)1

$stdenv/setup通常在stdenv.mkDerivation通用构建器一起使用时隐式调用(即,当builder属性未声明时),但可以编写自己的构建器并在构建过程中显式调用它

提示:这个答案显示了一种查找某个 Nix 函数的定义位置的方法(尽管它不是绝对可靠的)。

作为推论,shebang 指令指向的程序不会在这些位置(或无法从沙箱访问),但它们实际上在(或将在)Nix 商店中,因此路径需要是重新指向了他们在里面的位置。

注意:通用构建器从派生的输入中填充 PATH,因此必须确保将这些作为依赖项包含在内。

三、如何使用

3.1 隐式

如上所述,每当构建包时,在修复阶段由设置挂钩自动调用 - 除非通过设置变量(或与此相关的变量)选择退出此操作patchShebangs参阅Nixpkgs手册中控制修复阶段的变量)。patchShebangsAuto dontPatchShebangsdontFixup

提醒自己:6.4 Bash 条件表达式

3.1.0patchShebangs自动调用时使用什么脚本?

通常在包安装的脚本上(例如 to $out/bin)。

还是 Nixpkgs 标准库默认提供的那些?我认为这些必须足够通用才能在不同的平台上运行,以便 (1) 构建模板,以及 (2) 最后修补脚本 shebangs。(@jtojnar 证实了这个猜想,但本节需要参考,因此是小案例。)

3.1.1 如何使用控制构建阶段的变量?

将它传递给mkDerivation控制构建器的任何其他变量。

stdenv.mkDerivation {
  #...
  dontPatchShebangs = true;
  #...
}

3.2 明确

历史注释:最初,patchShebangs它不能在外部调用,但后来被提取以使其功能在其他构建阶段也可重用。

同样,来自实施中的评论:

# 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 脚本)上运行。这些可能是

  1. 来自正在包装的东西的来源
  2. 由一个人编写,在构建过程中用作助手2

来自网络的具体例子:


脚注

[1]:待办事项:详细了解沙盒是如何准确构建的,以及哪些是禁止的,哪些是允许的。引用@jtojnar 举一个例子:

/usr/bin/env,这在沙盒中也不可用。(为了方便起见,NixOS 仅在用户空间中具有此功能,但不会延续到 Nix 沙箱。.

[2]:@jtojnar 的评论:“是的,您不需要将它显式用于仅在运行时执行的脚本,因为这些将由隐式调用处理。


此线程中的所有链接(希望)都已保存到Internet Archive。(线程的配乐是这个 gem。)

于 2021-04-23T13:38:58.890 回答