如何诊断 nix 构建失败?
目前我看到的输出为:
nix build -v
warning: dumping very large path (> 256 MiB); this may run out of memory
building '/nix/store/fdrm6kbm68vld3bhfjizv684ck725lyf-blog.drv'...
builder for '/nix/store/fdrm6kbm68vld3bhfjizv684ck725lyf-blog.drv' failed with exit code 1; last 5 log lines:
unpacking sources
unpacking source archive /nix/store/s7r5vlvp49ad6a9d5hqhsiaxw691iyhf-Blog
source root is Blog
patching sources
configuring
[0 built (1 failed), 0.0 MiB DL]
error: build of '/nix/store/fdrm6kbm68vld3bhfjizv684ck725lyf-blog.drv' failed
我希望找到一些日志/错误来说明为什么它无法构建?
继自https://stackoverflow.com/a/47264375/1663462:
我尝试添加build-cache-failures = true;
到default.nix
但我仍然看不到输出:
nix-store --read-log
结果nix-store --query-failed-paths
是:
error: no operation specified
Try 'nix-store --help' for more information.
答案1
也可以看看:
- nix 构建调试- 在交互式 bash shell 中调试失败的 nix-build
- 在 nix-shell 中构建 stdenv 包在 nixpkgs 文档中
- Nix-build-phases:交互式运行 nix 构建阶段在尼克索斯的话语中
- 开发环境nix-shell在尼克斯维基中
- nixpkgs 中的 runPhase 函数
eval "${!curPhase:-$curPhase}"
cd "${sourceRoot:-.}"
- nixpkgs 中的 genericBuild 函数- 打电话
runPhase $curPhase
调试包的构建过程:
代替nix-build
nix-build -E 'with import <nixpkgs> {}; callPackage ./. {}'
运行nix-shell
进入构建环境
nix-shell -E 'with import <nixpkgs> {}; callPackage ./. {}'
然后运行构建阶段
# run build in tempdir
cd $(mktemp -d)
# dont install to /nix/store
for n in $outputs; do eval export $n=$PWD/result-$n; done
# https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh
phases="${prePhases[*]:-} unpackPhase patchPhase ${preConfigurePhases[*]:-} \
configurePhase ${preBuildPhases[*]:-} buildPhase checkPhase \
${preInstallPhases[*]:-} installPhase ${preFixupPhases[*]:-} fixupPhase installCheckPhase \
${preDistPhases[*]:-} distPhase ${postPhases[*]:-}";
echo writing nix-build-phases.txt
for curPhase in $phases; do
echo "eval \"\${$curPhase:-$curPhase}\""
if [ "$curPhase" = unpackPhase ]; then
echo '[ -n "${sourceRoot:-}" ] && chmod +x "${sourceRoot}"'
echo 'cd "${sourceRoot:-.}"'
fi
done >nix-build-phases.txt
echo "please manually run the build phases in nix-build-phases.txt"
echo
cat nix-build-phases.txt
示例 nix-build-phases.txt
eval "${unpackPhase:-unpackPhase}"
[ -n "${sourceRoot:-}" ] && chmod +x "${sourceRoot}"
cd "${sourceRoot:-.}"
eval "${patchPhase:-patchPhase}"
eval "${updateAutotoolsGnuConfigScriptsPhase:-updateAutotoolsGnuConfigScriptsPhase}"
eval "${configurePhase:-configurePhase}"
eval "${buildPhase:-buildPhase}"
eval "${checkPhase:-checkPhase}"
eval "${installPhase:-installPhase}"
eval "${fixupPhase:-fixupPhase}"
eval "${installCheckPhase:-installCheckPhase}"
eval "${distPhase:-distPhase}"
在此构建环境中,您可以
- 找出构建错误的原因(哪个构建阶段失败了?)
- 修改构建命令,例如重新定义
buildPhase
:运行type buildPhase
打印旧阶段、复制旧阶段、修改阶段、粘贴新阶段 - 运行修改后的构建命令。这可能比完全重建更快
注意:构建者可以执行不同的构建阶段。实际的构建阶段存储在变量中,例如prePhases
或preConfigurePhases
问题:构建脚本运行,set -e
因此它将在出现第一个错误时退出,但这会退出交互式 shell。这是 bash shell 的限制,因此理想情况下,我们将在 bash 调试器中运行构建脚本,在出现第一个错误时停止执行,修改命令,后退并重复执行命令,并允许检查状态。
# run build in tempdir
cd $(mktemp -d)
# dont install to /nix/store
for n in $outputs; do eval export $n=$PWD/result-$n; done
# https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh
phases="${prePhases[*]:-} unpackPhase patchPhase ${preConfigurePhases[*]:-} \
configurePhase ${preBuildPhases[*]:-} buildPhase checkPhase \
${preInstallPhases[*]:-} installPhase ${preFixupPhases[*]:-} fixupPhase installCheckPhase \
${preDistPhases[*]:-} distPhase ${postPhases[*]:-}";
# test
#patchPhase="echo test error in patchPhase; false"
donePhases=()
missingPhases=($phases)
for curPhase in $phases; do
# no. genericBuild does not "return 1" on error
#phases="$curPhase" genericBuild || break
echo
echo "# running $curPhase"
# FIXME this also traps suspend (Ctrl-Z)
trap '
echo "FIXME error in $curPhase"
echo "done phases:" ${donePhases[@]}
echo "missing phases:" ${missingPhases[@]}
echo "hit Enter to close the nix-shell"
read
' EXIT
set -e # exit on error
set -x # trace
eval "${!curPhase:-$curPhase}"
set +x
set +e
if [ "$curPhase" = unpackPhase ]; then
[ -n "${sourceRoot:-}" ] && chmod +x "${sourceRoot}"
cd "${sourceRoot:-.}"
fi
donePhases+=($curPhase)
missingPhases=(${missingPhases[@]:1})
done
答案2
阅读日志应该有效。你有具体说明推导过程吗? nix-store --read-log /nix/store/fdrm6kbm68vld3bhfjizv684ck725lyf-blog.drv
答案3
有一个--debug
选项以及一个可以提供附加信息的--print-build-logs
选项(打开nix build
但不是)。nix-build
关于具体问题 - 可能是这个错误:https://github.com/NixOS/nix/issues/2176
更多信息
https://releases.nixos.org/nix/nix-0.16/build/565033/download/1/manual/index.html#id494024
答案4
添加失败的breakpointHook
推导nativeBuildInputs
也是一种强大的技术——它可以让你与cntr
并探索派生构建失败时的环境。
感谢 jamesbrock 在 NixOS Discourse 上的发言,它的缺点是:
将包添加breakpointHook
到nativeBuildInputs
a 的mkDerivation
.
nativeBuildInputs = [ breakpointHook ];
安装中心
nix-env -i cntr
运行 Nix 构建命令,当它失败时,breakpointHook 将输出如下消息:
build failed in installPhase with exit code 1
To attach install cntr and run the following command as root:
cntr attach -t command cntr-/nix/store/6vwxqrwq5h1fd3nw4mc61wgk7rppn2qw-jupyterlab-extended
所以我们运行该命令根。 root 用户没有我们在 Nix 配置文件中安装的PATH
命令cntr
,因此请为其提供单用户安装的 cntr 的完整路径。
sudo /home/$USER/.nix-profile/bin/cntr attach -t command cntr-/nix/store/6vwxqrwq5h1fd3nw4mc61wgk7rppn2qw-jupyterlab-extended
现在我们在沉睡的尼克斯容器中。请注意,像和
这样的路径在此阶段与您常用的工具一起可用,但是它们位于当前目录 ( ) 下,而不是. (您可以像这样使用它们。)$out
$TMPDIR
/var/lib/cntr
/
cd $(echo $out | cut -c2-)
从这里,运行cntr exec
以完全加载构建环境。
/home/$USER/.nix-profile/bin/cntr exec
该$TMPDIR
目录是 Nix 为构建 10 创建临时目录的位置。
cd $TMPDIR
buildPhase
现在我们完全处于构建的上下文中,并且我们在 shell 中输入的任何命令都将如同我们在派生失败时在派生阶段(例如 )的一行中输入该命令一样。
我还想添加一些有关 BreakpointHook 的细节。这是一个非常强大的调试钩子@Mic92。
将 pkgs.breakpointHook 放入 buildInputs 中即可使其正常工作。如果出现故障,则会在控制台上打印出准确的“连接”命令。您可以使用此命令 (cntr) 将 shell 附加到构建环境中。要使用它,您必须能够与 cntr 一起运行 sudo (因此您应该在之前安装 cntr 包;-))。
您可以在 @Mic92 NixCon 演示文稿中找到更多有趣的细节:Jörg 'Mic92' Thalheim - 关于 Nix 沙箱和断点 (NixCon 2018)
这是手册相关部分的链接:https://nixos.org/manual/nixpkgs/stable/#breakpointhook