skip to content
WangWindow

使用 provides 避免 pacman 重复安装依赖

/ 5 min read

Table of Contents

有时我们已经通过官方压缩包、SDK 管理器或其他方式,在用户目录中安装了某个运行环境,但 pacman 并不知道它的存在。

例如,我已经手动安装了 Java,并将其加入了 PATH。此时 Java 命令可以正常使用,但在安装 Minecraft 启动器时,pacman 仍可能要求安装仓库中的 Java 软件包。

这是因为 pacman 判断依赖是否满足时,主要检查的是自己的本地软件包数据库,而不是扫描 PATH,也不会检查用户目录中是否存在对应程序。

一种解决方法是创建一个只包含软件包元数据的空包,通过 PKGBUILD 中的 provides 字段,告诉 pacman:

当前系统已经通过其他方式提供了这些依赖。

例如:

Terminal window
pkgname=facman
pkgver=1.0.0
pkgrel=1
pkgdesc='Virtual package providers for pacman dependency resolution'
arch=('any')
license=('MIT')
provides=(
'dotnet-sdk'
'netcat'
'nodejs=26.5.0'
'npm'
)
package() {
:
}

其中,provides 用来声明这个软件包能够提供哪些其他软件包或虚拟组件。安装 facman 后,当其他软件包依赖 dotnet-sdknetcatnpm 或符合版本要求的 nodejs 时,pacman 会认为这些依赖已经得到满足。provides 正是 PKGBUILD 官方支持的虚拟依赖机制。

package() 中只有一个 :,表示不安装任何实际文件。因此,facman 本质上只是一个元数据包:它不会安装 Node.js、.NET SDK 或其他运行环境,只会将 provides 信息注册到 pacman 的本地数据库中。

将上述内容保存为 PKGBUILD 后,可以执行:

Terminal window
makepkg -si

makepkg 会根据当前目录中的 PKGBUILD 生成 Arch 软件包,-i 会在构建完成后安装该软件包。

安装后,可以使用以下命令查看注册的虚拟依赖:

Terminal window
pacman -Qi facman

也可以检查某个依赖是否已经得到满足:

Terminal window
pacman -T dotnet-sdk npm netcat 'nodejs>=18'

如果没有任何输出,说明这些依赖在 pacman 看来均已满足。

关于版本

如果目标软件包只依赖包名:

Terminal window
depends=('npm')

那么下面的声明就足够了:

Terminal window
provides=('npm')

但如果目标软件包带有版本限制:

Terminal window
depends=('nodejs>=18')

那么 provides 也应声明一个具体版本:

Terminal window
provides=('nodejs=26.5.0')

provides 中应描述“当前提供的具体版本”,不能写成 nodejs>=18。依赖方会使用这个具体版本进行比较。

注意事项

这种方法只会改变 pacman 的依赖判断,不会真正提供对应的命令、动态链接库或运行环境。

因此,它适合下面这种情况:

  • 已经通过官方压缩包安装了 Java 或 .NET SDK;
  • 已经通过语言版本管理器安装了对应运行环境;
  • 系统中确实存在与目标软件兼容的替代实现;
  • 只是希望避免 pacman 再安装一份重复环境。

不建议为了减少下载量而随意伪造原生动态库依赖。假如软件运行时需要 libexample.so,仅仅添加:

Terminal window
provides=('example')

并不会创建这个动态链接库,软件仍然可能无法启动。

另外,这个包只需要在本地通过 makepkg 构建和安装,并不一定要上传到 AUR。AUR 主要用于共享用户维护的 PKGBUILD;其中的软件仍然需要由用户使用 makepkg 构建,再通过 pacman 安装。

参考资料