修复 FreeBSD 上的依赖

不知道你怎么样,但我经常更新我的包……而且数量多达一千多个。

% pkg info | wc -l
    1051

……不过这没什么,大多数都是我使用软件的依赖包。

例如,我需要 Openbox 和 X11,但为了使用它们,我需要 300 多个库和协议依赖,这很正常,这就是它的工作方式……不过有时升级之后,一两个应用程序会因为缺失依赖而无法启动。我会说这种情况大约每二十到三十次更新发生一次(1/20 – 1/30),非常罕见,而且即便发生,也很容易解决。我在 Linux 系统上也遇到过很多次,所以这不仅仅是 FreeBSD 的问题,这就是开源桌面/笔记本生态的运作方式 🙂。

今天的受害者是 Chromium。我平时一般使用 Firefox,但有时当某个页面在 Firefox 上表现异常时,我会用 Chromium 验证这个行为。我也把 Chromium 用作本地 .htm/.html/*.chm 文件的文件打开器(或者说文件浏览器)。但这次它无法启动,于是我去命令行检查出了什么问题。

% chrome
Shared object "libx264.so.155" not found, required by "libavcodec.so.58"

……缺失的依赖是库 libx264.so.155

鲁莽的符号链接

这种方法被认为是危险的,或者说是一种快速且粗糙的修复方式——它本身也可能引入其他问题——但在很多情况下,它可以暂时解决问题。

……而这正是它的作用——一个临时修复,直到 ffmpeg 包完成重建——这比执行 pkg upgrade 命令需要更长时间,但当我现在需要 Chromium 时,就是“现在”,而不是等 ffmpeg 包重建完成之后再说。这个问题的根源在于 FreeBSD 项目缺乏提供 lame 包的勇气。OpenBSD 的开发者没有这个问题,但 FreeBSD 的开发者有。因此,要在 ffmpeg 中支持 MP3,你必须先手动编译 lame 包,然后在 ffmpeg 中选择该选项,再将其重新构建为包……而且每次执行 pkg upgrade 命令都要重复这一过程……至少可以说这是非常麻烦的。

这就是我使用 pkg-recompile.sh 脚本的原因——为了避免每次更新包(大约每周两次)都手动重复上述操作。如果可以称之为“工作流程”,它大致是这样的:

# pkg upgrade
# pkg-recompile.sh build

那我们来验证一下,看看 Chromium 是否还有其他缺失的依赖。

所以 /usr/local/bin/chrome 只是一个包装脚本,让我们看看它的内容。

所以我们的真正二进制文件是 /usr/local/share/chromium/chrome,接下来用 ldd(8) 检查它。

依赖很多,我们直接用 grep(1) 筛选,示例如下。

只缺失了一个依赖——libx264.so.155。那我们就来修复它。

这里有一个稍新的版本 libx264.so.157,所以我们用它创建一个符号链接,命名为缺失的 libx264.so.155

现在应该能正常启动 Chromium 了。

没有出现任何 not found 的结果。

那我们就用 chrome 命令启动 Chromium。

一如既往,一切正常 🙂。

可以通过下面这张简单的截图直观地看到整个过程。

vermaden_2019-03-21_15-47-40.png

使用 /etc/libmap.conf 文件

与其创建符号链接——这种方法会全局生效——你也可以为二进制文件 /usr/local/share/chromium/chrome 单独创建一个合适的 libmap.conf 配置文件。

下面是仅针对 Chromium 浏览器的修复方法。

……与之等效、可全局生效的解决方案是使用符号链接,如下所示。

这种方法也更方便迁移或批量应用这些修改,而不需要复制符号链接。

修复 pkg(8) 数据库中的破损依赖

我在 Less Known pkg(8) Features 一文中已经写过,但为了选项的完整性,这里值得再提一次。

曾经有一次,缺失的依赖——涉及易受攻击的 www/libxul19 包——折磨了我一段时间。

我甚至已经绝望到想用 portmaster 重新编译所有东西。

我一开始使用了 portmaster --check-depends 命令,但在提示是否修复时选择了‘n’,因为那会不必要地降级很多包。

那我们来看 pkg(8) 显示的已安装包情况。

问题在于我们安装的是 www/libxul 而不是 www/libxul19,这也是为什么 portmaster(以及其他工具)会报错。

在引入 pkg(8) 之前,只需对整个 /var/db/pkg 目录及其“文件数据库”使用 grep -r 就很容易查到,但现在情况复杂得多,因为包数据库已经存储在 SQLite 数据库中。

使用 pkg shell 命令可以连接到该数据库。让我们看看能找到些什么。

所以现在我们知道,“deps”表可能就是我们要找的 ;)。

由于 pkg shell 在 SQLite“浏览”方面相当有限,我将直接使用 sqlite3 命令。所谓有限,是指你不能直接输入 pkg shell "select * from deps;" 查询,而是需要先启动 pkg shell,然后才能输入查询语句。

第二列是 name,所以我们可以尝试用它来查询。

现在我们已经定位到这个“有问题”的依赖条目,让我们稍微修改它,使其与实际已安装的包状态一致。

当然,你也可以使用“官方”方式,通过 pkg shell 命令来操作。

现在 portmaster 已经不再抱怨缺失依赖,一切正常。

完美!问题解决了 😉

……但 pkg(8) 本身已经提供了工具来处理这个问题 🙂

它叫做 pkg set,在 man pkg-set 中最有用的两个选项是:

在我们的例子中,可以使用以下命令:pkg set -o www/libxul19:www/libxul

不过不确定它是否会以同样的方式解决问题,因为我同时还更新了数据库中的版本信息。

使用 bsdadminscripts2 包中的 pkg_libchk

还有另一种方法可以修复或检查此类问题——那就是使用 bsdadminscripts2 包中的 pkg_libchk。请注意,这里有两个名称中带有 bsdadminscripts 的冲突包,需要区分清楚。

……只要你安装了 bsdadminscripts2,就无法再安装 bsdadminscripts,因为它们存在冲突。我之前已经安装了 bsdadminscripts2,但想在系统中添加 bsdadminscripts

下面是 Port/包 /usr/ports/ports-mgmt/bsdadminscripts2 的描述。

这个包正好有四个工具。

如果不带任何参数调用,它会检查系统中安装的所有包。

……所以如果只想对 Chromium 进行检查,需要指定 chromium 包,命令如下:

pkg_libchk 可以根据哪个包提供了哪些文件来获取缺失的依赖,或者生成需要重建的包列表。

使用 Provides 数据库

你也可以使用 pkg(8) 的“provides”数据库。

想了解如何为 pkg(8) 命令设置“provides”数据库,请查阅文章 Less Known pkg(8) Features

更新 1 – 重新整理整篇文章

古罗马哲学家塞涅卡曾说过——“在教别人的同时,我们也在学习。”——这句话非常正确——尤其是对本文而言。在我将文章发布到各处后,大家提醒我,仅仅创建符号链接并不是最好的方法。对此我接受指正,并增加了额外章节和方法,介绍如何在 FreeBSD(或 Linux/Illumos)系统上修复破损依赖。

最后更新于

这有帮助吗?