4.5.使用 Ports

ports 是由多组 Makefile、 补丁和描述文件构成的。每一组文件都可用来在 FreeBSD 上编译和安装一个单独的应用程序,并被称为 port

默认情况下,ports 本身是作为一个子目录存储在 /usr/ports 下。

警告

在安装和使用 ports 之前,请注意通常不建议将 ports 与通过 pkg 提供的二进制包一起使用来安装软件。pkg 跟踪的是 port tree 的季度分支版本,而不是 HEAD。HEAD 分支中的 port 与季度分支中的相比,依赖关系可能有所不同,这可能导致 pkg 安装的依赖关系与 ports 中的依赖关系发生冲突。如果必须同时使用 ports 和 pkg,那么请确保你的 ports 和 pkg 在的同一个 ports 分支上。

ports 包含软件类别的目录。在每一个类别中,都有针对各个应用程序的子目录。每个应用程序的子目录都包含了一组文件,这些文件告诉 FreeBSD 如何编译和安装这个程序,这被称为 ports 框架。每个 port 框架都包括这些文件和目录:

  • Makefile:包含指定应用程序应如何被编译以及其组件应安装在何处的代码。

  • distinfo: 包含为编译 port 而必须下载的文件的名称和校验和。

  • files/: 这个目录包含了程序在 FreeBSD 上编译和安装所需的任何补丁。这个目录还可能包含用于编译 port 的其他文件。

  • pkg-descr: 提供了关于对该程序更详细的说明。

  • pkg-plist: 包含所有将被 port 安装的文件的列表。它也会告诉 ports 系统在卸载时要删除哪些文件。

一些 ports 还包含 pkg-message 或其他文件来处理特殊情况。关于这些文件以及一般的 ports 的更多细节,请参考 FreeBSD Porter 的手册

port 中并不包括实际的源代码,也就是所谓的 distfile。编译 port 的 extract 部分会自动将下载的源代码保存到 /usr/ports/distfiles

4.5.1.安装 Ports

在使用 port 编译应用程序之前,必须首先安装 ports。如果在安装 FreeBSD 时没有安装 ports,可以使用下列方法来安装它:

Git 方法

如果需要对 ports 进行更多的控制,或需要维护本地的修改,或者运行 FreeBSD-CURRENT,可以使用 Git 来获取 ports。请参阅 The Git Primer 以了解关于 Git 的详细介绍。

  1. 在用来检查 ports 之前,必须先安装 Git。如果已经有了 ports 的副本,请像这样安装 Git:

# cd /usr/ports/devel/git
# make install clean

如果 ports 不可用,或者正在使用 pkg 管理软件包,那么可以将 Git 作为一个软件包来安装:

# pkg install git
  1. 查看一下 ports tree 的 HEAD 分支副本:

# git clone https://git.FreeBSD.org/ports.git /usr/ports
  1. 或者,查看一份季度分支的副本:

# git clone https://git.FreeBSD.org/ports.git -b 2023Q1 /usr/ports
  1. 根据需要,在初始化 Git 检出后更新 /usr/ports

# git -C /usr/ports pull
  1. 根据需要,将 /usr/ports 切换到不同的季度分支:

# git -C /usr/ports switch 2023Q1

4.5.2.安装 Ports

本节提供了关于使用 ports 来安装或删除软件的基本说明。关于可用的 make 目标和环境变量的详细的说明,可以在 ports(7) 中找到。

警告

在编译任何 port 之前,请务必按照前一节所述更新 ports。由于安装任何第三方软件都可能引入安全漏洞,因此建议首先检查 https://vuxml.freebsd.org/,以了解与该 port 有关的已知安全问题。另外,在安装新的 port 之前,可以运行 pkg audit -F。这个命令可以被配置为在每日安全系统检查中自动执行安全审计和漏洞数据库的更新。更多信息,请参阅 pkg-audit(8)periodic(8)

使用 ports 的前提是有一个正常的互联网连接。它还需要超级用户的权限。

要编译和安装这个 port,请切换到要安装的 port 的目录,然后在提示符下输入 make install。提示消息会显示进度:

# cd /usr/ports/sysutils/lsof
# make install
>> lsof_4.88D.freebsd.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
>> Attempting to fetch from ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/.
===>  Extracting for lsof-4.88
...
[extraction output snipped]
...
>> Checksum OK for lsof_4.88D.freebsd.tar.gz.
===>  Patching for lsof-4.88.d,8
===>  Applying FreeBSD patches for lsof-4.88.d,8
===>  Configuring for lsof-4.88.d,8
...
[configure output snipped]
...
===>  Building for lsof-4.88.d,8
...
[compilation output snipped]
...

===>  Installing for lsof-4.88.d,8
...
[installation output snipped]
...
===>   Generating temporary packing list
===>   Compressing manual pages for lsof-4.88.d,8
===>   Registering installation for lsof-4.88.d,8
===>  SECURITY NOTE:
      This port has installed the following binaries which execute with
      increased privileges.
/usr/local/sbin/lsof
#

由于 lsof 是一个需要提升权限才能运行的程序,所以在安装时将显示一个安全警告。安装完成后,将返回提示符。

一些 shell 保留了 PATH 环境变量中列出的目录中可用的命令的缓存,以加快对这些命令的可执行文件的查找操作。tcsh shell 的用户应该输入 rehash,这样就可以在不指定完整路径的情况下使用一个新安装的命令。在 sh shell 中使用 hash -r 来代替。更多信息请参考 shell 的文档。

在安装过程中,会创建一个工作子目录,其中包含了编译过程中使用的所有临时文件。删除这个目录可以节省磁盘空间,并在以后更新到较新版本的 port 时尽量减少出现问题的机会:

# make clean
===>  Cleaning for lsof-88.d,8
#

注意

为了省去这个多余的步骤,在编译 port 时应使用 make install clean

4.5.2.1.定制 Port 安装

一些 port 提供了编译选项,可以用来启用或禁用应用程序组件,提供安全选项,或允许其他定制。例子包括 www/firefoxsecurity/gpgme。如果这个 port 依赖于其他有可配置选项的 port,它可能会因为用户的互动而暂停数次,因为默认行为是提示用户从菜单中选择选项。为了避免这种情况,并在一个批次中完成所有的配置,可以在 port 的框架中运行 make config-recursive。然后,运行 make install [clean] 来编译和安装这个 port。

提示

当使用 config-recursive 时,要配置的 port 列表是由 all-depends-list 目标收集的。建议运行 make config-recursive 直到所有依赖的 port 选项都被设定,并且不再出现 port 选项菜单,以确定所有的依赖选项都被配置了。

有几种方法可以重新进入 port 的编译选项菜单,以便在 port 编译完成后添加、 删除或修改这些选项。一种方法是 cd 进入包含 port 的目录,然后输入 make config。另一个方法是使用 make showconfig。还有一个方法是执行 make rmconfig,它将删除所有选定的选项并让你重新开始设定。所有这些选项,以及其他选项,在 ports(7) 中都有详细的解释。

ports 系统使用 fetch(1) 来下载源文件,它支持各种环境变量。如果 FreeBSD 系统位于防火墙或 FTP/HTTP 代理之后,可能需要设置 FTP_PASSIVE_MODEFTP_PROXYFTP_PASSWORD 这些变量。请参阅 fetch(3) 以了解支持的变量的完整列表。

对于那些不能保持连接到互联网的用户来说,可以在 /usr/ports 中运行 make fetch,以获取所有的 distfiles,或在一个类别中,例如 /usr/ports/net,或在特定的 port 框架中运行。请注意,如果一个 port 有任何依赖关系,在一个类别或 port 框架中运行此命令将 不会 获取另一个类别中的 port 的 distfiles。相反,应该使用 make fetch-recursive 来获取一个 port 的所有依赖关系的 distfiles。

在少数情况下,例如当一个组织有个本地的 distfiles 仓库时,可以用变量 MASTER_SITES 来覆盖 Makefile 中指定的下载位置。在使用时,应指定备用的位置:

# cd /usr/ports/directory
# make >MASTER_SITE_OVERRIDE= \
ftp://ftp.organization.org/pub/FreeBSD/ports/distfiles/ fetch

变量 WRKDIRPREFIXPREFIX 可以覆盖默认的工作目录和目标目录。比如说:

# make WRKDIRPREFIX=/usr/home/example/ports install

将在 /usr/home/example/ports 中编译 port,并将一切文件安装到 /usr/local 中:

# make PREFIX=/usr/home/example/local install

将在 /usr/ports 中编译这个 port,并将其安装在 /usr/home/example/local。然后使用:

# make WRKDIRPREFIX=../ports PREFIX=../local install

将把这两者结合起来。

也可以把这些设置为环境变量。关于如何设置环境变量的说明,请参考你的 shell 的手册页。

4.5.3.移除已安装的 Port

可以通过 pkg delete 来卸载已安装的 port。可以在 pkg-delete(8) 手册中找到使用这一命令的例子。

另外,也可以在 port 的目录中运行 make deinstall

# cd /usr/ports/sysutils/lsof
# make deinstall
===>  Deinstalling for sysutils/lsof
===>   Deinstalling
Deinstallation has been requested for the following 1 packages:

    >lsof-4.88.d,8

The deinstallation will free 229 kB
[1/1] Deleting lsof-4.88.d,8... done

建议在卸载 port 的过程中阅读这些信息。如果这个 port 有任何依赖它的应用程序,这些信息将被显示出来,但卸载将继续进行。在这种情况下,为了防止依赖关系被破坏,建议重新安装该应用程序。

4.5.4.更新 Port

随着时间的推移,ports 中会出现更新的软件版本。本节介绍了如何确定哪些软件可以更新,以及如何执行更新。

要确定所安装的 port 是否有更新的版本,应使用“Git 方法”中说明的更新命令,确保安装了最新版本的 ports。下面的命令将列出已经安装的过时的 port:

# pkg version -l "<"

重要

在尝试更新之前,请从文件的顶部阅读 /usr/ports/UPDATING,以确定与上次更新 port 或安装系统最接近的日期。这个文件涉及了用户在更新 port 时可能遇到的各种问题和需要执行的额外步骤,包括诸如文件格式的变化、 配置文件位置的变化,以及与先前版本不兼容的情况。请注意任何与需要更新的 port 相匹配的说明,并在执行更新时遵循这些说明。

4.5.4.1.更新和管理 Port 的工具

ports 包含了几个实用程序来执行实际的更新。每一个都有它的优势和劣势。

过去,大多数安装都使用 Portmaster 或 Portupgrade。Synth 是一个较新的选择。

哪种工具最适合某个特定的系统,都由系统管理员来选择。在使用这些工具之前,建议先备份你的数据。

4.5.4.2.使用 Portmaster 更新 Port

ports-mgmt/portmaster 是一个非常迷你的工具,用于更新已安装的 port。它被设计用来使用 FreeBSD 基本系统中安装的工具,而不需要依赖其他 port 或数据库。要把这个工具作为一个 port 来安装:

# cd /usr/ports/ports-mgmt/portmaster
# make install clean

Portmaster 定义了四种类型的 port:

  • Root(根)port:没有依赖关系,也不是任何其他 port 的依赖关系。

  • Trunk(主干)port:没有依赖关系,但其他 port 依赖它。

  • Branch(分支)port:有依赖关系,其他 port 依赖于它。

  • Leaf(子)port:有依赖关系但没有其他 port 依赖它。

要列出这些类别并搜索更新:

# portmaster -L
===>>> Root ports (No dependencies, not depended on)
===>>> ispell-3.2.06_18
===>>> screen-4.0.3
        >===>>> New version available: screen-4.0.3_1
===>>> tcpflow-0.21_1
===>>> 7 root ports
...
===>>> Branch ports (Have dependencies, are depended on)
===>>> apache22-2.2.3
        >===>>> New version available: apache22-2.2.8
...
===>>> Leaf ports (Have dependencies, not depended on)
===>>> automake-1.9.6_2
===>>> bash-3.1.17
        >===>>> New version available: bash-3.2.33
...
===>>> 32 leaf ports

===>>> 137 total >installed ports
        >===>>> 83 have new versions available

该命令用于更新所有过时的 port:

# portmaster -a

注意

在默认情况下,Portmaster 在删除现有的 port 之前会做备份。如果新版本安装成功,Portmaster 将删除备份。使用 -b 可以指示 Portmaster 不自动删除备份。添加 -i 可以在交互式模式下启动 Portmaster,在更新每个 port 之前提示确认。还有许多其他选项可用。请阅读 portmaster(8) 的手册以了解它们的详细用法。

如果在更新过程中遇到错误,可以添加 -f 来更新和重建所有的 port:

# portmaster -af

Portmaster 也可以用来在系统中安装新的 port,在联编和安装新 port 之前更新所有的依赖关系。要使用这个功能,需要在 ports 中指定 port 的位置。

# portmaster shells/bash

关于 ports-mgmt/portmaster 的更多信息可以在其 pkg-descr 中找到。

4.5.4.3.使用 Portupgrade 更新 Port

ports-mgmt/portupgrade 是另一个可以用来更新 port 的工具。它安装了一套可以用来管理 port 的应用程序。而且,它依赖于 Ruby。要安装这个 port:

# cd /usr/ports/ports-mgmt/portupgrade
# make install clean

在使用这个工具进行更新之前,建议使用 pkgdb -F 扫描已安装的 port 列表,并修正它报告的所有不一致之处。

要更新系统中安装的所有过时的 port,请使用 portupgrade -a。另外,也可以使用-i来确认每一次的更新:

# portupgrade -ai

要更新一个指定的应用程序而不是所有可用的 port,请使用 portupgrade pkgname。包括 -R 是非常重要的,它可以首先更新指定应用程序所需的所有 port:

# portupgrade -R firefox

如果包含 -P,Portupgrade 会在 PKG_PATH 中列出的本地目录中搜索可用的软件包。如果本地没有可用的软件包,它就会从远程站点获取软件包。如果在本地找不到软件包或无法从远程获取,Portupgrade 将使用 ports。要完全避免使用 ports,请指定 -PP。这最后一组选项告诉 Portupgrade,如果没有可用的包,就放弃:

# portupgrade -PP gnome3

如果指定了 -P,则只需获取 port distfiles 或 packages,而不需要编译或安装任何东西,请使用 -F。关于所有可用开关的进一步信息,请参考 portupgrade 的手册。

关于 ports-mgmt/portupgrade 的更多信息可以在其 pkg-descr 中找到。

4.5.5.Ports 和磁盘空间

使用 ports 会随着时间的推移而耗尽磁盘空间。在编译和安装了一个 port 之后,在 ports 框架中运行 make clean 将清理临时 工作 目录。如果使用 Portmaster 来安装一个 port,它将自动删除这个目录,除非指定了 -K。如果安装了 Portupgrade,这个命令将删除在 ports 本地副本中发现的所有 工作 目录:

# portsclean -C

此外,过时的源码包文件会随着时间的推移在 /usr/ports/distfiles 中积累起来。要使用 Portupgrade 来删除所有不再被任何 port 引用的 distfiles:

# portsclean -D

Portupgrade 可以删除所有不被当前安装在系统上的任何 port 引用的 distfiles:

# portsclean -DD

如果安装了 Portmaster,请使用:

# portmaster --clean-distfiles

默认情况下,该命令是交互式的,提示用户确认是否应该删除 distfile。

除了这些命令之外,ports-mgmt/pkg_cutleaves 还会自动删除已安装的、不再需要的 port。