依赖项

自动依赖项解析是 emerge 提供的最有用的功能之一。

建议您按字母顺序对依赖项进行排序,将无条件依赖项归为一组,然后是所有条件依赖项。有一个例外:如果您要简化更改检查,可以按照上游列表对依赖项进行排序。一些项目可能具有不同的策略 - 如果您不确定,请咨询它们。

请参阅有关 Ebuild 修订 的以下部分,了解依赖项和修订之间的交互方式。

依赖项类型

CHOST 与 CBUILD

为了避免歧义,我们使用以下术语来指示交叉编译时不同的系统。它们除了字面意义(例如 $CHOST)之外,还用作整个系统的简写。

CBUILD
执行构建的系统。适用于 CBUILD 系统的依赖项可以在构建时执行。
CHOST
将执行该软件包的系统。交叉编译时,适用于 CHOST 的依赖项无法执行。

交叉编译时,CBUILD 和 CHOST 自然不同,不同类型的依赖项的实际安装路径也不同。

但是请注意,虽然交叉编译用于帮助解释这些概念,但它不是严格要求的。CBUILD 和 CHOST 可以针对完全相同的硬件,但安装到不同的 SYSROOT/ROOT 路径中。即使不是严格意义上的交叉编译,依赖项区分仍然适用。

构建依赖项

构建依赖项用于指定解包、修补、编译、测试或安装软件包所需的任何依赖项(但请参阅 隐式系统依赖项 以了解例外情况)。

从 EAPI 7 开始,构建依赖项被拆分为两个变量:BDEPENDDEPENDBDEPEND 指定适用于 CBUILD 的依赖项,即构建期间需要执行的程序,例如 virtual/pkgconfigDEPEND 指定 CHOST 的依赖项,即在构建的系统上需要找到的软件包,例如库和头文件。

在早期 EAPIs 中,所有构建依赖项都放置在 DEPEND 中。

运行时依赖项

RDEPEND ebuild 变量应指定运行时所需的任何依赖项。这包括库(动态链接时)、任何数据包以及(对于解释型语言)相关的解释器。

请注意,从二进制软件包安装时,只会检查 RDEPEND。因此,即使在 DEPEND 中也列出了项目,也必须包含它们。

RDEPEND 中但不在 DEPEND 中的项目理论上可以在目标软件包之后合并。Portage 目前没有这样做。

后依赖项

PDEPEND 变量指定在运行时并不严格要求立即满足的依赖项。它们可以在软件包之后合并。此变量仅用于解决循环依赖项,而在一般情况下应改用 RDEPEND

依赖项语法

基本依赖项语法

一个基本的 DEPEND 规范可能看起来像下面这样

DEPEND="dev-lang/ruby
	dev-ruby/ruby-gtk2
	dev-ruby/mysql-ruby"

每个软件包依赖项规范都是软件包的完整类别和名称。依赖项规范由任意空格隔开 - 惯例是每行有一个规范,以提高可读性。指定名称时,类别部分应视为必填项。

版本依赖项

有时需要特定版本的软件包。如果已知,则应指定它。一个简单的例子

DEPEND=">=dev-libs/openssl-0.9.7d"

这表明至少需要 openssl 的 0.9.7d 版本。

版本说明符

可用的版本说明符是

说明符 意义
>=app-misc/foo-1.23 需要 1.23 或更高版本。
>app-misc/foo-1.23 需要严格高于 1.23 的版本。
~app-misc/foo-1.23 需要 1.23 版本(或任何 1.23-r*)。
=app-misc/foo-1.23 需要 1.23 版本。如果可能,请使用 ~ 形式来简化修订版本升级。
<=app-misc/foo-1.23 需要 1.23 或更早版本。
<app-misc/foo-1.23 需要严格低于 1.23 的版本。

范围依赖项

要指定软件包的“2.x 版本(不是 1.x 或 3.x)”,需要使用星号后缀。这在以下情况中最常见

DEPEND="gtk? ( =x11-libs/gtk+-2* )"

请注意,等号是必需的,星号前面没有点。另请注意,在选择特定 SLOT 中的所有版本时,应使用 SLOT 依赖项(见下文)。

阻止程序

当两个软件包(软件包插槽、版本)无法同时安装时,可以使用阻止程序向包管理器公开此冲突。

阻止程序有两种:弱阻止程序强阻止程序

使用以下语法定义弱阻止程序

RDEPEND="!app-misc/foo"

包管理器将尝试自动解决此冲突。被弱阻止程序阻止的软件包可以在安装阻止它的软件包之后卸载。但是,它免除了通用文件的文件冲突检查。弱阻止程序通常用于解决软件包之间的文件冲突,并且仅在 RDEPEND 中有意义。

更具体地说,安装较新的软件包可能会覆盖属于被明确阻止的较旧软件包的任何冲突文件。当发生此类文件冲突时,冲突文件将不再属于较旧的软件包,并且在较旧的软件包最终被卸载后仍会保留安装状态。仅在较新的阻止软件包都合并到其之上之后才会卸载较旧的软件包。

如果在构建(安装)软件包之前严格需要解决阻止程序,则必须使用强阻止程序。在这种情况下,不允许临时同时安装冲突的软件包。强阻止程序使用以下语法表达

RDEPEND="!!app-misc/foo"

强阻止程序相应地适用于定义它们的依赖项类型。在 RDEPEND 中定义的阻止程序在软件包安装后一直生效(但不会阻止构建二进制软件包)。仅在 DEPEND 中定义的阻止程序仅在从源代码构建软件包时生效,并且可能不适用于安装软件包后或从二进制软件包安装软件包时。

强阻止程序最常见的用途是,另一个软件包的安装会导致构建失败。强阻止程序不用于阻止仅仅是文件冲突。

也可以阻止特定版本

RDEPEND="!<app-misc/foo-1.3"

阻止程序可以根据 USE 标志成为可选的,就像正常的依赖项一样。

添加到较旧 ebuild 中的阻止程序不应期望是追溯性的。如果用户已经安装了 ebuild,则不应期望 ebuild 的任何更改会产生任何影响。这意味着您应该将阻止程序添加到最新的 ebuild 中(即使在逻辑上看起来是反向的)。例如,某些版本的 Portage 不喜欢某些版本的 bash,但阻止程序被放入 bash 中,因为它是导致问题的较新的软件包。

SLOT 依赖项

要依赖特定的 SLOT,应将 :SLOT 附加到包名后,其中 'SLOT' 是所需包的 SLOT

DEPEND="qt5? ( dev-qt/qtcore:5 )
	gtk? ( x11-libs/gtk+:2 )

要依赖于 SLOT 中的特定版本或版本范围,我们使用

DEPEND="qt5? ( ~dev-qt/qtcore-5.15.2:5 )
	gtk? ( >=x11-libs/gtk+-2.24.9:2 )

槽运算符

EAPI=5 及更高版本中,您可以使用附加到包名的槽运算符来声明您的包在满足其运行时依赖关系的版本更新到具有不同槽或 子槽 的版本后是否应重新构建

  • := 表示任何槽都是可以接受的。此外,它还表明,如果与运行时依赖项最匹配的版本更新到具有不同槽或子槽的版本,则您的包应重新构建。
  • :* 表示任何槽都是可以接受的。此外,此槽运算符明确声明可以忽略槽或子槽的更改。
  • :SLOT= 表示仅接受 'SLOT' 槽。否则,它的行为与 := 运算符相同。也就是说,如果依赖项的子槽发生更改,则必须重建该包。
  • :SLOT 表示仅接受 'SLOT' 槽,并且可以忽略子槽的更改(如之前的 EAPI 中)。
  • :SLOT/SUBSLOT 表示对特定槽和子槽对的依赖关系,这对于安装需要具有与子槽相对应的特定 soname 版本的库的预构建二进制文件的包很有用。

例如

RDEPEND="media-libs/cogl:1.0=
	gnutls? ( >=net-libs/gnutls-2.8:= )"

表示仅接受 media-libs/cogl 的 '1.0' 槽,并且 media-libs/cogl 的子槽更改将导致依赖包重新构建。此外,它还意味着 net-libs/gnutls 的每个槽都是可以接受的,但任何槽更改都会导致重新构建。

:slot 依赖关系语法继续像 EAPI=4 或更早版本一样工作,即它表示仅接受特定的槽值,并且当依赖项的当前安装版本被具有不同子槽的版本替换时,该包不会崩溃。

例如

RDEPEND="dev-libs/foo:2=
    >=dev-libs/bar-0.9:=
    media-gfx/baz:*
    x11-misc/wombat:0"

表示当 foo:2>=bar-0.9 升级到具有不同子槽的版本时,应重新构建该包。另一方面,应忽略 baz 的槽或子槽的更改,并且应忽略 wombat:0 的子槽更改。

USE 条件依赖项

仅当设置了给定的 USE 标志时,才依赖于某个包

DEPEND="perl? ( dev-lang/perl )
	ruby? ( >=dev-lang/ruby-1.8 )
	python? ( dev-lang/python )"

也可以在给定的 USE 标志设置时依赖于某个包

RDEPEND="!crypt? ( net-misc/netkit-rsh )"

不应该用于禁用给定体系结构上的特定 USE 标志。为了做到这一点,体系结构团队应将其 USE 标志添加到 Gentoo 存储库的 profiles/arch 目录中的 use.mask 文件中。

这可以嵌套

DEPEND="!build? (
	>=sys-libs/ncurses-5.2-r2
	gcj? (
		>=media-libs/libart_lgpl-2.1
		gtk? (
			x11-libs/libXt
			x11-libs/libX11
			x11-libs/libXtst
			x11-proto/xproto
			x11-proto/xextproto
			>=x11-libs/gtk+-2.2
			x11-libs/pango
		)
	)
	nls? ( sys-devel/gettext )
)"

许多依赖项中的任何一个

要依赖于 foobar

DEPEND="|| ( app-misc/foo app-misc/bar )"

如果设置了 baz USE 标志,则要依赖于 foobar

DEPEND="baz? ( || ( app-misc/foo app-misc/bar ) )"

许多依赖项中的任何一个与 USE

假设 fnord 可以针对 foobar 构建。然后,当且仅当以下所有条件成立时,才不需要 USE 标志

  • fnord 合并到已安装 foo 但未安装 bar 的系统上。然后,foo 被取消合并,并且 bar 被安装。fnord 必须继续正常工作。
  • 在具有 foo 但没有 bar 的系统上制作的 fnord 的二进制包可以被带到具有 bar 但没有 foo 的系统上安装。

使用 USE 依赖项构建

可用的说明符是

说明符 意义
app-misc/foo[bar] foo 必须启用 bar。
app-misc/foo[bar,baz] foo 必须启用 bar 和 baz。
app-misc/foo[-bar,baz] foo 必须禁用 bar 并启用 baz。

还有一些用于条件情况的快捷方式

紧凑形式 等效扩展形式
app-misc/foo[bar?] bar? ( app-misc/foo[bar] ) !bar? ( app-misc/foo )
app-misc/foo[!bar?] bar? ( app-misc/foo ) !bar? ( app-misc/foo[-bar] )
app-misc/foo[bar=] bar? ( app-misc/foo[bar] ) !bar? ( app-misc/foo[-bar] )
app-misc/foo[!bar=] bar? ( app-misc/foo[-bar] ) !bar? ( app-misc/foo[bar] )

使用依赖项默认值

如果依赖项在新的包版本中引入了或删除了 USE 标志,则可以在使用依赖项规范中添加 (+)(-) 来定义在目标包中不存在该标志时的默认值。 (+) 表示假设缺少的标志已启用,(-) 表示相反。

例如,以下操作将把所有没有 threads 标志的 boost 版本视为已启用,并且所有没有 openmpgcc 版本视为已禁用

DEPEND="
	>=dev-libs/boost-1.48[threads(+)]
	sys-devel/gcc[openmp(-)]"

检查依赖项的提示

确保包的所有依赖项都已完成非常重要

查看已安装的二进制文件/库
使用 scanelf -n(来自 app-misc/pax-utils)或 objdump -p(来自 sys-devel/binutils)之类的工具来列出 DT_NEEDED 条目。app-portage/iwdevtools 和 portage 自身的 qa-unresolved-soname-deps 功能 可以帮助找到这些内容。
查看 configure.ac
在这里查找包的检查。要注意的事情是 pkg-config 检查或检查特定版本的 AM_* 函数。
查看包含的 .spec 文件
查看包含的 .spec 文件以了解相关依赖项是一个很好的指示。但是,不要相信它们是依赖项的最终完整列表。
查看应用程序/库网站
查看应用程序网站以了解他们建议需要的可能依赖项。
阅读包的 READMEINSTALL
它们通常还包含有关构建和安装包的有用信息。
请记住非二进制依赖项,例如 pkg-config、文档生成程序等。此类程序通常属于 BDEPEND
通常,构建过程需要一些依赖项,例如 intltool、libtool、pkg-config、doxygen、scrollkeeper、gtk-doc 等。确保这些都明确说明。同样,此类依赖项通常属于 BDEPEND
在 chroot、容器和虚拟机中测试
查找丢失依赖项的可靠方法是在贫乏的环境中测试您的 ebuild。Chroot、容器、虚拟机和 dev-util/ebuildtester 可以实现这一点。

隐式系统依赖项

所有软件包都对整个 @system 集隐式地依赖于编译时和运行时。因此,除了需要特定版本或软件包(例如,glibc 超过 uclibc)之外,没有必要,也不建议指定对工具链软件包(如 gcclibc 等)的依赖关系。请注意,此规则也需要考虑 flexzliblibtool 之类的软件包,这些软件包并非在每个配置文件中都包含在 @system 集中。例如,嵌入式配置文件没有在 @system 中包含 zliblibtool 的 ABI 可能发生更改并破坏构建顺序,flex 可能在将来从 @system 集中删除。

但是,包含在 @system 集中或依赖于 @system 集软件包的软件包,通常应包含完整的依赖关系列表(不包括引导软件包)。这使得从阶段 1 或阶段 2 压缩包安装时 emerge -e @system 成为可能。

测试依赖项

软件包通常具有可选依赖项,这些依赖项仅在运行测试时才需要。这些应该在 DEPEND 后面指定 USE 标志。通常,'test' USE 标志用于此目的。

由于当未安装测试依赖项时测试可能会失败,因此在这种情况下应禁用测试阶段。这可以通过 RESTRICT 变量中的 USE 条件来实现。

如果在测试时必须启用/禁用其他可选功能,则可以设置 REQUIRED_USE 来表达这一点。

# Define some USE flags
IUSE="debug test"

# Require debug support when tests are enabled
REQUIRED_USE="test? ( debug )"

# Disable test phase when test USE flag is disabled
RESTRICT="!test? ( test )"

# Running tests requires 'foo' to be installed
DEPEND="test? ( dev-util/foo )"

循环依赖

如果一个或多个软件包的(可能间接的)依赖关系依赖于软件包本身,就会发生循环依赖。这会创建一个依赖关系循环,从技术上讲,每个软件包都必须在另一个软件包之前安装。例如,如果软件包 A 依赖于 B,B 依赖于 C,而 C 依赖于 A,那么软件包管理器就无法在 C 之前安装 A,也无法在 A 之前安装 C。

有三种循环依赖

  1. 如果只有一个软件包严格需要在另一个软件包之前安装,就会发生循环依赖。例如,dev-python/certifi 严格要求 dev-python/setuptools 进行构建,但后一个软件包需要前者才能实现某些运行时功能。因此,dev-python/certifi 可以比另一个软件包晚安装。PDEPEND 用于表达这一点并自动解决循环依赖关系。
  2. 如果循环仅适用于其中一个软件包上的 USE 标志的某些组合,就会发生循环依赖。例如,在 dev-python/setuptools 中运行测试需要许多软件包,这些软件包需要先安装 dev-python/setuptools。可以通过用户调整其中一个软件包上的 USE 标志来解决这种循环依赖,例如,通过禁用 dev-python/setuptools 上的测试,并在最初安装依赖关系后重新启用它们。
  3. 无法使用常规方法解决的循环依赖。例如,dev-util/cmake 曾经依赖于 dev-libs/jsoncpp,而后者使用前者来构建。解决这种依赖关系通常需要有条件地捆绑其中一个依赖关系,或提供备用引导路径。

虽然应避免循环依赖,但对于仅用于测试的依赖关系,可以例外。类似于上面 dev-python/setuptools 测试的示例,如果一个软件包需要直接或间接地使用自身才能运行其测试,那么通常可以保留原样。如果可以的话,您应该修复它,但不要为此付出太多努力。

间接依赖

始终列出您的软件包需要构建和正确运行的每个直接依赖关系。不要依赖依赖关系链来满足依赖关系要求。例如,一个软件包需要 dep1dep2,但 dep1 也依赖于 dep2。您可能考虑只添加 dep1,因为它目前也拉取了 dep2,但在将来,dep1 可能会将 dep2 作为依赖关系删除,或者使其与 USE 标志一起使用。这将导致您的 ebuild 无法构建。