依赖项
自动依赖项解析是 emerge
提供的最有用的功能之一。
建议您按字母顺序对依赖项进行排序,将无条件依赖项归为一组,然后是所有条件依赖项。有一个例外:如果您要简化更改检查,可以按照上游列表对依赖项进行排序。一些项目可能具有不同的策略 - 如果您不确定,请咨询它们。
请参阅有关 Ebuild 修订 的以下部分,了解依赖项和修订之间的交互方式。
依赖项类型
CHOST 与 CBUILD
为了避免歧义,我们使用以下术语来指示交叉编译时不同的系统。它们除了字面意义(例如 $CHOST)之外,还用作整个系统的简写。
- CBUILD
- 执行构建的系统。适用于 CBUILD 系统的依赖项可以在构建时执行。
- CHOST
- 将执行该软件包的系统。交叉编译时,适用于 CHOST 的依赖项无法执行。
交叉编译时,CBUILD 和 CHOST 自然不同,不同类型的依赖项的实际安装路径也不同。
但是请注意,虽然交叉编译用于帮助解释这些概念,但它不是严格要求的。CBUILD 和 CHOST 可以针对完全相同的硬件,但安装到不同的 SYSROOT/ROOT 路径中。即使不是严格意义上的交叉编译,依赖项区分仍然适用。
构建依赖项
构建依赖项用于指定解包、修补、编译、测试或安装软件包所需的任何依赖项(但请参阅 隐式系统依赖项 以了解例外情况)。
从 EAPI 7 开始,构建依赖项被拆分为两个变量:BDEPEND
和 DEPEND
。BDEPEND
指定适用于 CBUILD 的依赖项,即构建期间需要执行的程序,例如 virtual/pkgconfig
。 DEPEND
指定 CHOST 的依赖项,即在构建的系统上需要找到的软件包,例如库和头文件。
在早期 EAPIs 中,所有构建依赖项都放置在 DEPEND
中。
依赖项语法
基本依赖项语法
一个基本的 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
中有意义。
更具体地说,安装较新的软件包可能会覆盖属于被明确阻止的较旧软件包的任何冲突文件。当发生此类文件冲突时,冲突文件将不再属于较旧的软件包,并且在较旧的软件包最终被卸载后仍会保留安装状态。仅在较新的阻止软件包都合并到其之上之后才会卸载较旧的软件包。
DEPEND
中的弱阻止程序无法正常工作。虽然 Portage 表面上会将软件包排队以供删除,但它不会将其内容从文件冲突检查中排除。始终将您的弱阻止程序包含在 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 )
)"
许多依赖项中的任何一个
要依赖于 foo
或 bar
DEPEND="|| ( app-misc/foo app-misc/bar )"
如果设置了 baz
USE
标志,则要依赖于 foo
或 bar
DEPEND="baz? ( || ( app-misc/foo app-misc/bar ) )"
使用 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] ) |
检查依赖项的提示
确保包的所有依赖项都已完成非常重要
- 查看已安装的二进制文件/库
- 使用
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
文件以了解相关依赖项是一个很好的指示。但是,不要相信它们是依赖项的最终完整列表。 - 查看应用程序/库网站
- 查看应用程序网站以了解他们建议需要的可能依赖项。
- 阅读包的
README
和INSTALL
- 它们通常还包含有关构建和安装包的有用信息。
- 请记住非二进制依赖项,例如 pkg-config、文档生成程序等。此类程序通常属于
BDEPEND
。 - 通常,构建过程需要一些依赖项,例如 intltool、libtool、pkg-config、doxygen、scrollkeeper、gtk-doc 等。确保这些都明确说明。同样,此类依赖项通常属于
BDEPEND
。 - 在 chroot、容器和虚拟机中测试
- 查找丢失依赖项的可靠方法是在贫乏的环境中测试您的 ebuild。Chroot、容器、虚拟机和
dev-util/ebuildtester
可以实现这一点。
隐式系统依赖项
所有软件包都对整个 @system
集隐式地依赖于编译时和运行时。因此,除了需要特定版本或软件包(例如,glibc
超过 uclibc
)之外,没有必要,也不建议指定对工具链软件包(如 gcc
、libc
等)的依赖关系。请注意,此规则也需要考虑 flex
、zlib
和 libtool
之类的软件包,这些软件包并非在每个配置文件中都包含在 @system
集中。例如,嵌入式配置文件没有在 @system
中包含 zlib
,libtool
的 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。
有三种循环依赖
- 如果只有一个软件包严格需要在另一个软件包之前安装,就会发生循环依赖。例如,
dev-python/certifi
严格要求dev-python/setuptools
进行构建,但后一个软件包需要前者才能实现某些运行时功能。因此,dev-python/certifi
可以比另一个软件包晚安装。PDEPEND
用于表达这一点并自动解决循环依赖关系。 - 如果循环仅适用于其中一个软件包上的 USE 标志的某些组合,就会发生循环依赖。例如,在
dev-python/setuptools
中运行测试需要许多软件包,这些软件包需要先安装dev-python/setuptools
。可以通过用户调整其中一个软件包上的 USE 标志来解决这种循环依赖,例如,通过禁用dev-python/setuptools
上的测试,并在最初安装依赖关系后重新启用它们。 - 无法使用常规方法解决的循环依赖。例如,
dev-util/cmake
曾经依赖于dev-libs/jsoncpp
,而后者使用前者来构建。解决这种依赖关系通常需要有条件地捆绑其中一个依赖关系,或提供备用引导路径。
虽然应避免循环依赖,但对于仅用于测试的依赖关系,可以例外。类似于上面 dev-python/setuptools
测试的示例,如果一个软件包需要直接或间接地使用自身才能运行其测试,那么通常可以保留原样。如果可以的话,您应该修复它,但不要为此付出太多努力。