Product SiteDocumentation Site

5.2. 软件包元信息

Debian 软件包不仅是一个待安装文件的归档。它是一个更大结构的一部分,它描述与其它 Debian 软件包的关系(依赖、冲突、建议)。在软件包生命周期的不同阶段(安装、删除、升级),它还提供执行命令的脚本。软件包中的这些数据供包管理工具使用,但不是打包软件的一部分,称为“元信息”(关于其它信息的信息)。

5.2.1. 描述:control 文件

该文件使用一个类似电子邮件头(由 RFC_2822 定义)的结构。例如,apt 包的 control 文件看起来是这样的:
$ apt-cache show apt
Package: apt
Version: 1.4.8
Installed-Size: 3539
Maintainer: APT Development Team <deity@lists.debian.org>
Architecture: amd64
Replaces: apt-utils (<< 1.3~exp2~)
Depends: adduser, gpgv | gpgv2 | gpgv1, debian-archive-keyring, init-system-helpers (>= 1.18~), libapt-pkg5.0 (>= 1.3~rc2), libc6 (>= 2.15), libgcc1 (>= 1:3.0), libstdc++6 (>= 5.2)
Recommends: gnupg | gnupg2 | gnupg1
Suggests: apt-doc, aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), powermgmt-base, python-apt
Breaks: apt-utils (<< 1.3~exp2~)
Description-en: commandline package manager
 This package provides commandline tools for searching and
 managing as well as querying information about packages
 as a low-level access to all features of the libapt-pkg library.
 .
 These include:
  * apt-get for retrieval of packages and information about them
    from authenticated sources and for installation, upgrade and
    removal of packages together with their dependencies
  * apt-cache for querying available information about installed
    as well as installable packages
  * apt-cdrom to use removable media as a source for packages
  * apt-config as an interface to the configuration settings
  * apt-key as an interface to manage authentication keys
Description-md5: 9fb97a88cb7383934ef963352b53b4a7
Tag: admin::package-management, devel::lang:ruby, hardware::storage,
 hardware::storage:cd, implemented-in::c++, implemented-in::perl,
 implemented-in::ruby, interface::commandline, network::client,
 protocol::ftp, protocol::http, protocol::ipv6, role::program,
 scope::application, scope::utility, sound::player, suite::debian,
 use::downloading, use::organizing, use::searching, works-with::audio,
 works-with::software:package, works-with::text
Section: admin
Priority: important
Filename: pool/main/a/apt/apt_1.4.8_amd64.deb
Size: 1231676
MD5sum: 4963240f23156b2dda3affc9c0d416a3
SHA256: bc319a3abaf98d76e7e13ac97ab0ee7c238a48e2d4ab85524be8b10cfd23d50d

5.2.1.1. 依赖:Depends

依赖关系是在软件包头部的 Depends 域中定义的,它是软件包能够正常运行所需要满足的一系列条件。包管理工具诸如 apt 依靠这个信息来安装该软件所依赖的恰当版本的库。对于每一项依赖,可以限定依赖的版本范围来满足条件。换句话说,可以这样表达:我们需要版本号等于或者大于“2.15”的 libc6 软件包(写作 “libc6 (>= 2.15)”)。版本比较操作符使用如下:
  • <<:小于;
  • <=:小于或等于;
  • =:等于(注意, “2.6.1” 不等于 “2.6.1-1”);
  • >=:大于或等于;
  • >>:大于。
In a list of conditions to be met, the comma serves as a separator. It must be interpreted as a logical “and”. In conditions, the vertical bar (“|”) expresses a logical “or” (it is an inclusive “or”, not an exclusive “either/or”). Carrying greater priority than “and”, it can be used as many times as necessary. Thus, the dependency “(A or B) and C” is written A | B, C. In contrast, the expression “A or (B and C)” should be written as “(A or B) and (A or C)”, since the Depends field does not tolerate parentheses that change the order of priorities between the logical operators “or” and “and”. It would thus be written A | B, A | C.
相依性系统是保证程序顺利运作的良好机制,但它也有另个用法 「元软件包」。这些空的软件软件包内容只有相依性的说明。由元软件包维护者把一群程序的相依性描述在其中;例如,apt install meta-package 将自动安装所有用到元软件包相依的文件。gnomekde-fulllinux-image-amd64 软件包就是元软件包之一。

5.2.1.2. 冲突:冲突字段

Conflicts 冲突 字段指示不能与其共存的其它软件包。最常见的理由是两个软件包使用相同的名称,或在同个 TCP 端口提供相同的服务,或会隐藏彼此的运作。
dpkg 不会安装冲突的软件包,除非新软件包指明 “取代” 被冲突的软件包,dpkg 才会以新的软件包取代旧的软件包。apt 总是遵循您的指示:若选择安装新软件包,则自动移除造成问题的旧软件包。

5.2.1.3. 不相容性:中断字段

中断 Breaks 字段有一个影响和冲突字段类似,但它具有特殊的意义。它标志着一个包的安装会将另外一个包(或者是特定版本)中断掉。通常而言,两个包之间的不兼容是短暂的,中断关系会特别指出那些不兼容的版本。
已经中断现有软件包时,dpkg 将拒绝安装并且 apt 将更新软件包至新的版本试图解决此问题 (通常可解决此问题,并再度兼容)。
不向后兼容的更新可能会发生这种情况:如果新版本与旧版本的功能不在另一个程序中做特别规定,这将导致故障。中断字段会防止用户继续运行从而遇到这些问题。

5.2.1.4. 预备好的条目:预备字段

这个字段引入了一个很有意思的“虚拟包”的概念。它有很多的角色,但有两个特别重要。第一个是由使用虚拟包关联到的一个通用的服务(包“预备”了这些服务)。第二个表示一个包完全取代了另外一个,所以它也能满足依赖性要求。因此,可以创建一个替换而不必使用相同的包名称的包。
5.2.1.4.1. 提供一个“服务”
让我们以范例详述第一个案子:postfixsendmail 之类的邮件服务器都 “提供” mail-transport-agent 虚拟软件包。因此需要启用该等服务的软件包 (如:smartlistsympa 之类的邮件列表管理器) 只要在其相依性里叙明需要 mail-transport-agent 而不是指明还不兼容的可能解决方案清单 (如 postfix | sendmail | exim4 | …)。更进一步来说,在同个机器安装两个邮件服务器是没有用的,因此每个软件包都声明与 mail-transport-agent 虚拟软件包冲突。系统忽略冲突的两个软件包,但技术上可以禁止同时安装两个邮件服务器。
5.2.1.4.2. 和另一个软件包的可交互性
The Provides field is also interesting when the content of a package is included in a larger package. For example, the libdigest-md5-perl Perl module was an optional module in Perl 5.6, and has been integrated as standard in Perl 5.8 (and later versions, such as 5.24 present in Stretch). As such, the package perl has since version 5.8 declared Provides: libdigest-md5-perl so that the dependencies on this package are met if the user has Perl 5.8 (or newer). The libdigest-md5-perl package itself has eventually been deleted, since it no longer had any purpose when old Perl versions were removed.
使用了预备字段来避免中断依赖性关系

图 5.1. 使用了预备字段来避免中断依赖性关系

这个功能非常有用,因为它是永远不可能预料到变化莫测的发展,它不能够调整重命名,或者其他自动替换过的软件,所以它是必要的。
5.2.1.4.3. 过去的限制
虚拟软件包曾有很多限制,最麻烦的是没有版本编号。从上例可知,这种 Depends: libdigest-md5-perl (>= 1.6) 相依性,尽管在 Perl 5.10 里存在,但包管理系统仍认为不满足其相依性 — 虽然实际上已满足了。但是包管理系统不知道相依性没问题,只好选择风险最小的做法,假设其版本是不匹配的。
This limitation has been lifted in dpkg 1.17.11, and is no longer relevant in Stretch. Packages can assign a version to the virtual packages they provide with a dependency such as Provides: libdigest-md5-perl (= 1.8).

5.2.1.5. 替换文件:替换字段

Replaces 字段指出在其他软件包的文件,但该软件包也合理地取代他们。如果没有指明,dpkg 失败,说明它不能覆写另个软件包的文件 (技术上来说,虽可以强迫使用 --force-overwrite 选项,但这不是标准选项)。因此在加入该字段之前,先允许维护者确认潜在可能的问题,并要求维护者先研究它。
当软件包名称变更时,或者当一个软件包包含在另外一个的时候,此字段的使用是合理的。这也发生在维护者决定从来自相同的源码包的大量二进制包里分发出文件:一个替换的文件不再属于旧的软件包,只有新的才属于。
如果已安装软件包的所有文件都被替换了,那么该软件包将认为将被删除掉。最后,这个字段会鼓励dpkg命令去删除替换掉有冲突的包。

5.2.2. 配置脚本

除了控制文件之外,每个Debian软件包可能在control.tar.gz的存档中包含了一些脚本,这些脚本在软件包处理的不同的阶段被dpkg调用。Debian政策描述了一些可能的细节,在可能的情况下,指定脚本调用它们所收到的参数。这些顺序可能比较复杂,因为如果脚本中任何一步出现问题的时候,dpkg进程会通过取消安装或者卸载来尝试恢复到一个令人满意的状态(只要是可能的)。
在一般情况下,preinst脚本会在安装软件包前执行,而postinst会稍候执行。同样,prerm会在移除一个软件包的之前被调用,postrm 则随后执行。更新软件包相当于是清除掉以前的旧版本并且安装新的软件包。所以在这里我们不可能来详细描述所有的可能的方案,但我们将讨论最常见的两种:安装/更新和移除。

5.2.2.1. 安装和升级

这里告诉你,安装的时候发生了什么(或者是更新)
  1. 对于升级,dpkg会调用old-prerm 升级 新版本.
  2. 还是对于升级,dpkg执行new-preinst 升级 旧版本;对于第一个安装,它会执行 new-preinst 安装。它可能会增加旧版本的最后一个参数,如果软件包已经被安装或者是删除了(但没有清除合并掉旧版本,那么这个配置文件会被保留)。
  3. 新的软件包文件被解压。如果文件已经存在,就被会替换,同时会产生一个临时的备份副本。
  4. 对于更新,dpkg执行old-postrm 升级 新版本
  5. dpkg更新所有的内部数据(文件列表,配置脚本等),并删除被替换文件的备份。这是一条不归路: ) dpkg将不能够再访问回退到之前状态所需要的所有元素。
  6. dpkg 将更新配置文件,无法自动管理此工作时,要求用户做决定。详情在此 第 5.2.3 节 “校验,配置文件列表”
  7. 最后,dpkg 通过执行 new-postinst configure 最近一次配置的版本号 对软件包进行配置。

5.2.2.2. 软件包移除

这里是当移除一个软件包的时候发生了什么:
  1. dpkg 调用prerm 移除
  2. dpkg 移除了所有的软件包文件,只剩下了配置文件和配置的脚本。
  3. dpkg 运行 postrm remove。移除所有配置脚本,保留 postrm。若用户未选择 “清除” 选项,则工作完成。
  4. 对于一个完整的清除包(由dpkg --purgedpkg -P发出的),配置文件也将会被删除,同时一些副本(*.dpkg-tmp,*.dpkg-old,*.dpkg-new)和缓存文件也会被删除掉;dpkg这时会执行postrm purge
config 脚本补充前述的 4 个脚本,软件包以 debconf 取得配置用的信息。安装过程中,此脚本以 debconf 指令询问用户详细的问题。把回应记录在 debconf 数据库供未来的参考。在安装之前先由 apt 逐一运行该等脚本,归纳问题与回答。事前与事后安装脚本可使用该等信息回应用户的期望。

5.2.3. 校验,配置文件列表

除了稍早提过的维护者脚本与控制数据外,在 Debian 软件包内的 control.tar.gz 可能包括若干有趣的文件。首先,md5sums,包括软件包内所有文件的 MD5 校验。它的优点是允许 dpkg --verify (详情见 第 14.3.3.1 节 “Auditing Packages with dpkg --verify) 检查该等文件在安装后是否被修改。若此文件不存在,dpkg 将在安装时动态产生一个 (并且如同其他控制文件般保存在 dpkg 数据库)。
conffiles 列出必须当配置文件处理的软件包文件。管理员可修改配置文件,升级软件包时 dpkg 将保留这些变动。
实际上,在这种情况下,dpkg的行为会尽可能地智能:如果两个版本之间并没有改变标准的配置文件,那么dpkg就什么也不会作。但是,如果文件已经被修改,它会尝试更新此文件。这会产生两种可能的情况:一是管理员没有碰配置文件,在这种情况下dpkg会自动安装新版本;二是文件已经被修改了,在这种情况下dpkg会询问管理员希望使用哪个版本(旧版本或者新的)。为了帮助用户作出选择,dpkg会提供“差异”,这会显示两个版本之间的差异。如果用户选择保留旧的版本,新的将被存储在文件夹的同一个位置并以.dpkg-dist为后缀名的文件中。另外一个可能的操作是由暂时中断的dpkg来编辑该文件,并试图重新恢复相关的修改(之前被验证的差异)。