<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
  <!ENTITY % general-entities SYSTEM "../general.ent">
  %general-entities;
]>

<sect1 id="ch-system-pkgmgt">
  <?dbhtml filename="pkgmgt.html"?>

  <title>软件包管理</title>

  <!--para>Package Management is an often requested addition to the LFS Book. A
  Package Manager allows tracking the installation of files making it easy to
  remove and upgrade packages. As well as the binary and library files, a
  package manager will handle the installation of configuration files.  Before
  you begin to wonder, NO&mdash;this section will not talk about nor recommend
  any particular package manager. What it provides is a roundup of the more
  popular techniques and how they work. The perfect package manager for you may
  be among these techniques or may be a combination of two or more of these
  techniques. This section briefly mentions issues that may arise when upgrading
  packages.</para-->
  <para>软件包管理是一个经常被人请求添加到 LFS 手册中的内容。
	  包管理器可以跟踪软件包安装的文件，
	  这样就可以很容易地删除或者更新软件包。
	  和二进制程序、库文件一样，包管理器也会处理软件包安装的配置文件。
	  在您开始想入非非的时候，不！ —— 本节不会讨论或推荐任何特定的包管理器。
	  本节对软件包管理的流行技术及其工作原理进行综述，对您来说，
	  完美的包管理器可能是以下的某个技术，或者可能是几个技术的结合。
	  本节还将简要提到在升级软件包时可能遇到的问题。</para>

  <!--para>Some reasons why no package manager is mentioned in LFS or BLFS
  include:</para-->
  <para>LFS 或 BLFS 不采用任何包管理器的原因有：</para>

  <itemizedlist>
    <listitem>
      <!--para>Dealing with package management takes the focus away from the goals
      of these books&mdash;teaching how a Linux system is built.</para-->
      <para>处理包管理器会偏离本书的重点目标 —— 讲述如何构建 Linux 系统。
	  </para>
    </listitem>

    <listitem>
      <!--para>There are multiple solutions for package management, each having
      its strengths and drawbacks.  Including one that satisfies all audiences
      is difficult.</para-->
      <para>存在多种软件包管理的解决方案，它们各有优缺点，
		  很难找到一种让所有读者满意的方案。</para>
    </listitem>
  </itemizedlist>

  <!--para>There are some hints written on the topic of package management. Visit
  the <ulink url="&hints-index;">Hints Project</ulink> and see if one of them
  fits your need.</para-->
  <para>在 LFS 的 <ulink url="&hints-index;">Hints Project</ulink>
	  中有许多关于软件包管理的提示，您可以在其中查找，
	  看看有没有符合您需要的方案。</para>

  <sect2>
    <title>升级问题</title>

    <!--para>A Package Manager makes it easy to upgrade to newer versions when they
    are released. Generally the instructions in the LFS and BLFS Book can be
    used to upgrade to the newer versions. Here are some points that you should
    be aware of when upgrading packages, especially on a running system.</para-->
    <para>包管理器可以在软件包新版本发布后容易地完成升级。一般来说，
		使用 LFS 或者 BLFS 手册中的指令即可升级软件包。
		下面是您在升级时必须注意的重点，特别是升级正在运行的系统时。
	</para>

    <itemizedlist>
      <listitem>
        <!--para>If Glibc needs to be upgraded to a newer version, (e.g.  from
        glibc-2.19 to glibc-2.20, it is safer to rebuild LFS.  Though you
        <emphasis>may</emphasis> be able to rebuild all the packages in their
		dependency order, we do not recommend it.  </para-->
		<para>如果需要升级 Glibc (例如从 Glibc-2.19 升级到 Glibc-2.20），
			最安全的方法是重新构建 LFS 。尽管您<emphasis>或许</emphasis>
			能按依赖顺序重新构建所有软件包，但我们不推荐这样做。</para>
      </listitem>

      <listitem>
        <!--para>If a package containing a shared library is updated, and if the
        name of the library changes, then all the packages dynamically linked
        to the library need to be recompiled to link against the newer library.
        (Note that there is no correlation between the package version and the
        name of the library.) For example, consider a package foo-1.2.3 that
        installs a shared library with name
        <filename class='libraryfile'>libfoo.so.1</filename>. Say you upgrade
        the package to a newer version foo-1.2.4 that installs a shared library
        with name <filename class='libraryfile'>libfoo.so.2</filename>. In this
        case, all packages that are dynamically linked to
        <filename class='libraryfile'>libfoo.so.1</filename> need to be
        recompiled to link against
        <filename class='libraryfile'>libfoo.so.2</filename>. Note that you
        should not remove the previous libraries until the dependent packages
        are recompiled.</para-->
		<para>如果更新了一个包含共享库的软件包，而且共享库的名称发生改变，
			那么所有动态链接到这个库的软件包都需要重新编译，
			以链接到新版本的库。
			（注意，软件包的版本和共享库的名称没有关系。）
			例如，如果一个软件包 foo-1.2.3 安装了名为
			<filename class="libraryfile">libfoo.so.1</filename>
			的共享库，您把该软件包升级到了新版本 foo-1.2.4，它安装了名为
			<filename class="libraryfile">libfoo.so.2</filename>
			的共享库。那么，所有链接到
			<filename class="libraryfile">libfoo.so.1</filename>
			的软件包都要重新编译以链接到
			<filename class="libraryfile">libfoo.so.2</filename>。
			注意，在重新编译这些软件包之前，您不能删除旧版本的库。</para>
		<note><title>译注</title>
		<para>文中的<quote>共享库的名称</quote>应解释为 ELF 文件中的
			DT_SONAME，即 <command>ldd</command> 命令在箭头前输出的内容。
			根据<ulink url="https://semver.org">语义化版本</ulink>所述，
			共享库主版本号的递增表示 API 与之前版本不兼容，
			故主版本号往往被包含在共享库名称中，例如
			<filename class="libraryfile">libfoo.so.2</filename>
			中的 2 。
		</para>
		</note>
      </listitem>
    </itemizedlist>

  </sect2>

  <sect2>
    <title>软件包管理技术</title>

    <!--para>The following are some common package management techniques. Before
    making a decision on a package manager, do some research on the various
    techniques, particularly the drawbacks of the particular scheme.</para-->
	<para>以下是几种常见的软件包管理技术，在决定使用某种包管理器前，
		请研读这些技术，特别是要了解特定技术的不足。</para>

    <sect3>
      <title>这都在我的脑袋里！</title>

      <!--para>Yes, this is a package management technique. Some folks do not find
      the need for a package manager because they know the packages intimately
      and know what files are installed by each package. Some users also do not
      need any package management because they plan on rebuilding the entire
      system when a package is changed.</para-->
      <para>您没有看错，这是一种包管理技术。有些人觉得不需要管理软件包，
		  因为他们十分了解软件包，知道每个软件包安装了什么文件。
		  有的用户则计划每次有软件包发生变动时就重新构建系统，
		  所以不需要管理软件包。</para>

    </sect3>

    <sect3>
      <title>安装到独立目录</title>

      <!--para>This is a simplistic package management that does not need any extra
      package to manage the installations. Each package is installed in a
      separate directory. For example, package foo-1.1 is installed in
      <filename class='directory'>/usr/pkg/foo-1.1</filename>
      and a symlink is made from <filename>/usr/pkg/foo</filename> to
      <filename class='directory'>/usr/pkg/foo-1.1</filename>. When installing
      a new version foo-1.2, it is installed in
      <filename class='directory'>/usr/pkg/foo-1.2</filename> and the previous
      symlink is replaced by a symlink to the new version.</para-->
      <para>这是一种最简单的软件包管理方式，
		  它不需要任何额外的软件来控制软件包的安装。
		  例如，软件包 foo-1.1 将会被安装在
		  <filename class="directory">/usr/pkg/foo-1.1</filename>，
		  然后创建一个到该目录的符号链接 <filename>/usr/pkg/foo</filename>。
		  在安装新版本 foo-1.2 的时候，把它安装到
		  <filename class="directory">/usr/pkg/foo-1.2</filename>，
		  然后把之前的符号链接替换，使其链接到新版本。</para>

      <!--para>Environment variables such as <envar>PATH</envar>,
      <envar>LD_LIBRARY_PATH</envar>, <envar>MANPATH</envar>,
      <envar>INFOPATH</envar> and <envar>CPPFLAGS</envar> need to be expanded to
      include <filename>/usr/pkg/foo</filename>. For more than a few packages,
      this scheme becomes unmanageable.</para-->
      <para><envar>PATH</envar>、<envar>LD_LIBRARY_PATH</envar>、
		  <envar>MANPATH</envar>、<envar>INFOPATH</envar> 和
		  <envar>CPPFLAGS</envar> 等环境变量需要被扩充，以包含
		  <filename>/usr/pkg/foo</filename>。一旦软件包的数量较多，
		  这种架构就会变得无法管理。</para>

    </sect3>

    <sect3>
      <title>软链接风格的软件包管理</title>

      <!--para>This is a variation of the previous package management technique.
      Each package is installed similar to the previous scheme. But instead of
      making the symlink, each file is symlinked into the
      <filename class='directory'>/usr</filename> hierarchy. This removes the
      need to expand the environment variables. Though the symlinks can be
      created by the user to automate the creation, many package managers have
      been written using this approach. A few of the popular ones include Stow,
      Epkg, Graft, and Depot.</para-->
      <para>这是前一种软件包管理技术的变种。
		  将各个软件包同样安装在独立的目录中，但不建立目录的软链接，
		  而是把其中的每个文件链接到
		  <filename class="directory">/usr</filename> 目录树中对应的位置，
		  这样就不需要修改环境变量。这些链接可以由用户自己创建，
		  也可以自动化进行，一些流行的包管理器如 Stow、Epkg、Graft 和
		  Depot 使用这种管理方式。</para>

      <!--para>The installation needs to be faked, so that the package thinks that
      it is installed in <filename class="directory">/usr</filename> though in
      reality it is installed in the
      <filename class="directory">/usr/pkg</filename> hierarchy. Installing in
      this manner is not usually a trivial task. For example, consider that you
      are installing a package libfoo-1.1. The following instructions may
      not install the package properly:</para-->
      <para>安装过程需要伪装，使得软件包认为它处于
		  <filename class="directory">/usr</filename> 中，尽管它实际上被安装
		  在 <filename class="directory">/usr/pkg</filename> 目录结构中。
		  这样安装软件包一般不是简单的任务，例如考虑安装软件包 libfoo-1.1，
		  下面的指令可能不能正确安装该软件包：</para>

<screen role="nodump"><userinput>./configure --prefix=/usr/pkg/libfoo/1.1
make
make install</userinput></screen>

      <!--para>The installation will work, but the dependent packages may not link
      to libfoo as you would expect. If you compile a package that links against
      libfoo, you may notice that it is linked to
      <filename class='libraryfile'>/usr/pkg/libfoo/1.1/lib/libfoo.so.1</filename>
      instead of <filename class='libraryfile'>/usr/lib/libfoo.so.1</filename>
      as you would expect. The correct approach is to use the
      <envar>DESTDIR</envar> strategy to fake installation of the package. This
      approach works as follows:</para-->
      <para>尽管安装本身可以进行，
		  但依赖于它的软件包可能不会像你期望的那样链接 libfoo 库。
		  如果要编译一个依赖于 libfoo 的软件包，您可能发现它链接到了
		  <filename class="libraryfile">/usr/pkg/libfoo/1.1/lib/libfoo.so.1</filename>
		  而不是您期望的 <filename class="libraryfile">/usr/lib/libfoo.so.1</filename>。
		  正确的做法是使用 <envar>DESTDIR</envar> 策略伪装软件包的安装过程，
		  就像下面这样：</para>

<screen role="nodump"><userinput>./configure --prefix=/usr
make
make DESTDIR=/usr/pkg/libfoo/1.1 install</userinput></screen>

      <!--para>Most packages support this approach, but there are some which do not.
      For the non-compliant packages, you may either need to manually install the
      package, or you may find that it is easier to install some problematic
      packages into <filename class='directory'>/opt</filename>.</para-->
      <para>多数软件包可以这样安装，但有些不能。对于那些不兼容的软件包，
		  您要么亲自动手安装，要么更简单地把一些出问题的软件包安装在
		  <filename class="directory">/opt</filename> 中。</para>

    </sect3>

    <sect3>
      <title>基于时间戳的管理</title>

      <!--para>In this technique, a file is timestamped before the installation of
      the package. After the installation, a simple use of the
      <command>find</command> command with the appropriate options can generate
      a log of all the files installed after the timestamp file was created. A
      package manager written with this approach is install-log.</para-->
      <para>在这个方案中，安装一个软件包之前，为它创建一个时间戳文件。
		  在安装后，用一行简单的 <command>find</command> 命令，
		  加上正确的参数，就能生成安装日志，
		  包含在时间戳文件创建以后安装的所有文件。
		  有一个采用这个方案的包管理器叫做 install-log 。</para>

      <!--para>Though this scheme has the advantage of being simple, it has two
      drawbacks. If, during installation, the files are installed with any
      timestamp other than the current time, those files will not be tracked by
      the package manager. Also, this scheme can only be used when one package
      is installed at a time. The logs are not reliable if two packages are
      being installed on two different consoles.</para-->
      <para>尽管这种方式很简单，但它有两个缺点。如果在安装过程中，
		  某些文件没有以当前时间作为时间戳安装，它们就不能被包管理器跟踪。
		  另外，只有每次只安装一个软件包时才能使用这种技术，
		  如果在两个终端中同时安装两个不同的软件包，
		  它们的安装日志就不可靠了。</para>

    </sect3>

    <sect3>
      <title>追踪安装脚本</title>

      <!--para>In this approach, the commands that the installation scripts perform
      are recorded.  There are two techniques that one can use:</para>

      <para>The <envar>LD_PRELOAD</envar> environment variable can be set to
      point to a library to be preloaded before installation.  During
      installation, this library tracks the packages that are being installed by
      attaching itself to various executables such as <command>cp</command>,
      <command>install</command>, <command>mv</command> and tracking the system
      calls that modify the filesystem. For this approach to work, all the
      executables need to be dynamically linked without the suid or sgid bit.
      Preloading the library may cause some unwanted side-effects during
      installation. Therefore, it is advised that one performs some tests to
      ensure that the package manager does not break anything and logs all the
      appropriate files.</para-->
      <para>在这种方式中，安装脚本执行的命令被记录下来。
		  有两种技术可以进行记录：</para>

	  <para>在安装前设置 <envar>LD_PRELOAD</envar> 环境变量，
		  将其指向一个库以在安装过程中预加载它。在安装过程中，
		  这个库将自身附加在<command>cp</command>、
		  <command>install</command>、<command>mv</command> 等可执行文件上，
		  跟踪修改文件系统的系统调用。如果要使用这种方法，
		  所有需要跟踪的可执行文件必须是动态链接的，且没有设定
		  suid 和 sgid 位。预加载动态库可能在安装过程中导致不希望的副作用，
		  因此建议先进行一些测试，以确保包管理器不会造成破坏，
		  并且记录了所有应该记录的文件。
	  </para>


      <!--para>The second technique is to use <command>strace</command>, which
      logs all system calls made during the execution of the installation
      scripts.</para-->
      <para>第二种技术是使用 <command>strace</command>，
		  它能够记录安装脚本执行过程中的所有系统调用。</para>
    </sect3>

    <sect3>
      <title>创建软件包存档</title>

      <!--para>In this scheme, the package installation is faked into a separate
      tree as described in the Symlink style package management. After the
      installation, a package archive is created using the installed files.
      This archive is then used to install the package either on the local
      machine or can even be used to install the package on other machines.</para-->
      <para>在这种架构中，软件包被伪装安装到一个独立的目录树中，
		  就像软链接风格的软件包管理那样。
		  在安装后，使用被安装的文件创建一个软件包存档，
		  它可以被用来在本地机器甚至其他机器上安装该软件包。</para>

      <!--para>This approach is used by most of the package managers found in the
      commercial distributions. Examples of package managers that follow this
      approach are RPM (which, incidentally, is required by the <ulink
      url="http://refspecs.linuxfoundation.org/lsb.shtml">Linux
      Standard Base Specification</ulink>), pkg-utils, Debian's apt, and
      Gentoo's Portage system.  A hint describing how to adopt this style of
      package management for LFS systems is located at <ulink
      url="&hints-root;fakeroot.txt"/>.</para-->
	  <para>大多数商业发行版的包管理器采用这种策略，例如
		  RPM （值得一提的是，它被
		  <ulink url="http://refspecs.linuxfoundation.org/lsb.shtml">
			  Linux Standard Base 规则 </ulink> 所要求），pkg-utils、
		  Debian 的 apt、Gentoo 的 Portage 系统）等。
		  LFS Hint 中的一条提示描述了如何为 LFS 系统适用这种管理方式：
		  <ulink url="&hints-root;fakeroot.txt"/>。</para>

      <!--para>Creation of package files that include dependency information is
      complex and is beyond the scope of LFS.</para-->
      <para>创建包含依赖关系信息的软件包文件十分复杂，超过了 LFS 的范畴。
	  </para>

      <!--para>Slackware uses a <command>tar</command> based system for package
      archives.  This system purposely does not handle package dependencies
      as more complex package managers do.  For details of Slackware package
      management, see <ulink
      url="http://www.slackbook.org/html/package-management.html"/>.</para-->
	  <para>Slackware 使用一个基于 <command>tar</command>
		  的系统创建软件包档案。和更复杂的包管理器不同，
		  该系统有意地没有涉及软件包依赖关系。
		  如果想了解 Slackware 包管理器的详细信息，阅读
		  <ulink url="http://www.slackbook.org/html/package-management.html"
			  />。</para>
    </sect3>

    <sect3>
      <title>基于用户的软件包管理</title>

      <!--para>This scheme, unique to LFS, was devised by Matthias Benkmann, and is
      available from the <ulink url="&hints-index;">Hints Project</ulink>. In
      this scheme, each package is installed as a separate user into the
      standard locations. Files belonging to a package are easily identified by
      checking the user ID. The features and shortcomings of this approach are
      too complex to describe in this section. For the details please see the
      hint at <ulink url="&hints-root;more_control_and_pkg_man.txt"/>.</para-->
      <para>这种架构是 LFS 特有的，由 Matthias Benkmann 提出，可以在
		  <ulink url="&hints-index;">Hints Project</ulink> 查阅。
		  在该架构中，每个软件包都由一个单独的用户安装到标准位置。
		  只要检查文件所有者，就能找出属于一个软件包的所有文件。
		  它的优缺点十分复杂，不适合在本节讨论，详细信息请阅读
		  <ulink url="&hints-root;more_control_and_pkg_man.txt"/>。</para>

    </sect3>

  </sect2>

  <sect2>
    <title>在多个系统上部署 LFS</title>

    <!--para>One of the advantages of an LFS system is that there are no files that
    depend on the position of files on a disk system.  Cloning an LFS build to
    another computer with the same architecture as the base system is as
    simple as using <command>tar</command> on the LFS partition that contains
    the root directory (about 250MB uncompressed for a base LFS build), copying
    that file via network transfer or CD-ROM to the new system and expanding
    it.  From that point, a few configuration files will have to be changed.
	Configuration files that may need to be updated include:-->
	<para>LFS 系统的一项优势是，没有依赖于磁盘系统中文件位置的文件。
		将构建好的 LFS 系统复制到另一台具有相同硬件架构的计算机很简单，
		只要用 <command>tar</command> 命令把包含根目录的 LFS 分区打包
		（未压缩的情况下，一个基本的 LFS 系统需要 250 MB），
		然后通过网络传输或者刻成光盘，复制到新的系统上，再展开即可。
		这时，个别配置文件需要修改，可能需要更新的配置文件有：
    <filename>/etc/hosts</filename>,
    <filename>/etc/fstab</filename>,
    <filename>/etc/passwd</filename>,
    <filename>/etc/group</filename>,
    <phrase revision="systemd">
      <filename>/etc/shadow</filename>, 以及
      <filename>/etc/ld.so.conf</filename>。
    </phrase>
    <phrase revision="sysv">
      <filename>/etc/shadow</filename>,
      <filename>/etc/ld.so.conf</filename>,
      <filename>/etc/sysconfig/rc.site</filename>,
      <filename>/etc/sysconfig/network</filename>, 以及
      <filename>/etc/sysconfig/ifconfig.eth0</filename>。
    </phrase>
    </para>

    <!--para>A custom kernel may need to be built for the new system depending on
    differences in system hardware and the original kernel
    configuration.</para-->
    <para>由于系统硬件和原始内核配置的区别，
		可能需要为新系统重新配置并构建内核。</para>

    <note><!--para>There have been some reports of issues when copying between
    similar but not identical architectures. For instance, the instruction set
    for an Intel system is not identical with an AMD processor and later
    versions of some processors may have instructions that are unavailable in
	earlier versions.</para-->
    <para>有一些报告反映称，
		在架构相近但不完全一致的计算机之间拷贝 LFS 系统时出现问题。
		例如，Intel 系统使用的指令集和 AMD 处理器不完全相同，
		且较新的处理器可能包含旧处理器没有的指令。</para>
	</note>

	<note><title>译注</title>
		<para>据译者所知，LFS 中唯一默认进行机器相关优化的软件包是
			GMP-&gmp-version;。在编译该软件包时遵循构建指示中的
			<quote>注意</quote> 框，即可构建通用的库文件。
			然后注意整个构建过程不要使用 <option>-march</option> 选项，
			构建出的 LFS 系统就应该可以拷贝到架构相近
			（<userinput>uname -m</userinput> 输出相同结果）
			的机器上。</para>
	</note>


    <!--para>Finally the new system has to be made bootable via <xref
    linkend="ch-bootable-grub"/>.</para-->
	<para>最后，按照 <xref linkend="ch-bootable-grub"/> 中的指示，
		为新系统配置引导加载器。</para>

  </sect2>

</sect1>
