我已经使我的 Guix 系统完全是声明性的,总是通过guix package -m mymanifest.scm
.
有时,由于依赖关系冲突,这会失败。例如,现在gcc-toolchain
我的清单中有数十个其他软件包,并且显示此消息:
guix package: error: profile contains conflicting entries for gcc-toolchain
guix package: error: first entry: [email protected] /gnu/store/rfm800pq3q2midj29a4xlikdzjp1ps2l-gcc-toolchain-12.3.0
guix package: error: second entry: [email protected] /gnu/store/ks87cpc36kh8hqwr569pks4yrzfl7mnv-gcc-toolchain-11.3.0
hint: You cannot have two different versions or variants of `gcc-toolchain' in the same profile.
我想gcc-toolchain
清单中包含的是 12.3.0,并且其他一些包具有[email protected]
(间接)依赖项。但我不知道那是哪个包。
在这种特殊情况下,问题很容易解决,因为我也包含gcc
在清单中,这导致了警告package 'gcc' has been superseded by 'gcc-toolchain'
,并且删除gcc
似乎已经解决了问题。
但是,我想要一种更通用的适用方法来查找“有问题的”包。也就是说,给定一个清单文件,例如mymanifest.scm
,我如何找出给定包(例如[email protected]
,)通过哪个依赖链最终出现在配置文件中?
我通常会进行二分搜索,只需注释掉(或返回)一半的包,然后查看问题何时消失(或重新出现),但这是一个手动且繁琐的过程。
我自己可以自动化执行此操作的丑陋天真的方法是循环遍历所有包,调用guix graph
每个包,然后 grep 查找有问题的依赖项。更好的办法是弄清楚guix graph
正在做什么,并针对整个清单执行此操作。或者也许将清单转换为包(空,除了依赖项),然后调用guix graph
它。但可能有更好的方法。
答案1
总之:您可以通过单独构建清单的子集、从guix build -m manifest.scm
每个清单中列出的包的存储地址获取、循环它们并使用 grepguix gc --requisites
搜索它们的递归依赖项来暂时防止冲突。
由于您的配置文件当前无法构建,因此您应该将尝试添加的新软件包与它们冲突的旧软件包分开。或者,如果冲突发生在新包中,则将它们分开。包如何分发并不重要,重要的是要将您想要检查的所有包成功安装在商店中(以便您可以使用guix gc --requisites
)以及一些清单,您可以从中以编程方式获取它们的路径。
首先在每个清单上运行guix build
一次,以确保其成功构建并避免处理解析编译日志。然后第二次,它只会输出清单中包含的包的路径:
$ guix build -m manifest.scm
/gnu/store/jsk7igg8kd48blg5d6psb0rg120v68gw-xdot-1.1
/gnu/store/4dzv8avq7jyzybqvn3bj3c3bildi2pcc-graphviz-7.0.1-doc
/gnu/store/vsnrha979rs4sgmv2ynqvzd9dr5mj2mc-graphviz-7.0.1
然后,您可以循环访问此列表以guix gc --requisites
调用每个包,并搜索您感兴趣的依赖项(其在存储中的名称,如错误消息中所示)。这是一个例子fish
:
for manifest in manifest1.scm manifest2.scm
for package in (guix build -m $manifest)
if guix gc -R $package | grep -q '/gnu/store/ks87cpc36kh8hqwr569pks4yrzfl7mnv-gcc-toolchain-11.3.0'
echo $package
end
end
end
它将根据 递归地列出清单中的所有包[email protected]
。
可能与问题没有直接关系,但为了完整性:
如果您需要搜索商店中已有的配置文件的依赖项,并且您不能/不想使用guix build
(如果您没有其清单,或者 guix 需要重新下载 GB 的构建工具)等):您还可以从配置文件中恢复原始包列表。
一般来说,如果某个配置文件没有被垃圾收集,那么 中将会有一个指向它的链接/var/guix/profiles/per-user/
。如果您正在查找guix package -m mymanifest.scm
(其上次成功构建,不包含冲突的包)使用的配置文件,您可以在商店中找到地址:
$ readlink -f ~/.guix-profile
/gnu/store/…-profile
获得配置文件的路径后,第二步是查找原始清单中的包的路径。guix gc --references /gnu/store/…-profile
似乎还列出了它们的一些依赖项。为了仅获取您显式安装的软件包,我的技巧是使用软件包列表的缩进/gnu/store/…-profile/manifest
:第一级软件包有 6 个空格,它们的依赖项有 10 个,等等:
grep -E '^ {6}"/gnu/store/' /gnu/store/…-profile/manifest | cut -d'"' -f 2
然后你会得到与 相同的列表guix build
,减去由具有多个输出的包引起的双精度(例如上面示例中的 graphviz)。