27.6.从源代码更新 FreeBSD
相比于使用二进制更新,从源代码编译更新 FreeBSD 有几项优势。代码可以通过选项编译以利用特定硬件。部分基本系统可以使用非默认设置构建,或者在不需要或不想要的情况下完全省略。尽管构建过程比直接安装二进制更新花费更长的时间,但它能完全定制,生成量身定制的 FreeBSD 版本。
27.6.1. 快速开始
这是通过从源代码编译更新 FreeBSD 的典型步骤的快速参考。后续章节将详细说明该过程。
警告
从 mergemaster(8) 切换到 etcupdate(8) 时,首次运行可能会错误地合并更改,生成虚假的冲突。为防止这种情况,在更新源代码并构建新世界之前,执行以下步骤:
# etcupdate extract ① # etcupdate diff ②
① 引导 /etc 文件的数据库;有关更多信息,请参见 etcupdate(8)。
② 引导数据库后检查差异。删除任何不再需要的本地更改,以减少未来更新时发生冲突的可能性。
更新和构建
# git -C /usr/src pull ① 检查 /usr/src/UPDATING ② # cd /usr/src ③ # make -j4 buildworld ④ # make -j4 kernel ⑤ # shutdown -r now ⑥ # etcupdate -p ⑦ # cd /usr/src ⑧ # make installworld ⑨ # etcupdate -B ⑩ # shutdown -r now ⑪① 获取最新的源代码版本。有关获取和更新源代码的更多信息,请参见 更新源代码。
② 检查 /usr/src/UPDATING 文件,了解从源代码构建之前或之后是否需要手动执行的步骤。
③ 进入源代码目录。
④ 编译世界,即编译除内核以外的所有内容。
⑤ 编译并安装内核。这相当于
make buildkernel installkernel。⑥ 重启系统以使用新内核。
⑦ 更新并合并 /etc/ 中的配置文件,准备 installworld 安装。
⑧ 进入源代码目录。
⑨ 安装世界。
⑩ 更新并合并 /etc/ 中的配置文件。
⑪ 重启系统以使用新构建的世界和内核。
27.6.2. 准备源代码更新
阅读 /usr/src/UPDATING 文件。任何在更新之前或之后需要执行的手动步骤,都将在此文件中说明。
27.6.3. 更新源代码
FreeBSD 的源代码位于 /usr/src/ 目录。更新此源代码的首选方法是通过 Git 版本控制系统。验证源代码是否已纳入版本控制:
这表明 /usr/src/ 目录已纳入版本控制,并且可以使用 git(1) 更新:
如果目录最近未被更新过,更新过程可能需要一些时间。完成后,源代码将是最新的,可以开始下一节说明的构建过程。
注意
获取源代码:
如果输出显示
fatal: not a git repository,说明文件丢失或使用了不同的方法安装。需要重新克隆源代码。
表 1. FreeBSD 版本和存储库分支
uname -r 输出
存储库路径
说明
X.Y-RELEASE
releng/X.Y
发布版本,仅包含关键的安全和错误修复补丁。该分支推荐给大多数用户。
X.Y-STABLE
stable/X
发布版本及该分支的所有后续开发更新。STABLE 指的是应用二进制接口(ABI)不发生变化,因此早期版本编译的软件仍然可以在 FreeBSD 13-STABLE 上运行。例如,编译并运行在 FreeBSD 13.1 上的软件仍可以在后续的 FreeBSD 13-STABLE 上运行。STABLE 分支偶尔会有影响用户的错误或不兼容情况,但通常这些问题会迅速修复。
X-CURRENT
main
FreeBSD 最新的未发布开发版本。CURRENT 分支可能包含重大错误或不兼容,仅供专业用户使用。
使用 uname(1) 确定正在使用的 FreeBSD 版本:
根据 FreeBSD 版本和存储库分支,更新 13.2-RELEASE 的源代码使用的存储库路径为 releng/13.2。此路径在克隆源代码时使用:
① 将旧目录移到其他位置。如果该目录中没有本地修改,可以删除它。
② FreeBSD 版本和存储库分支 中的路径已添加到存储库 URL 中。第三个参数是源代码在本地系统上的目标目录。
27.6.4. 从源代码构建
世界(即操作系统的所有部分,除了内核)需要先编译,以提供更新的工具来构建内核。然后编译内核本身:
编译后的代码会写入 /usr/obj 目录。
这些是基本步骤。控制构建的其他选项将在下面说明。
27.6.4.1. 执行干净的构建
FreeBSD 构建系统的某些版本会将先前编译的代码保留在临时对象目录 /usr/obj 中。这可以通过避免重新编译未更改的代码来加速后续的构建。要强制重新构建所有内容,请在开始构建之前使用 cleanworld:
27.6.4.2. 设置构建任务的数量
在多核处理器上增加构建任务的数量可以提高构建速度。使用 sysctl hw.ncpu 来确定核心数量。由于处理器和不同版本的 FreeBSD 使用的构建系统有所不同,因此测试是唯一能确定不同任务数量对构建速度影响的可靠方法。作为起点,考虑使用核心数量的一半到两倍。可以使用 -j 来指定任务数量。
示例 1. 增加构建任务数量
使用四个任务来构建世界和内核:
27.6.4.3. 仅构建内核
如果源代码发生更改,必须先完成 buildworld。之后,可以随时运行 buildkernel 来构建内核。要仅构建内核:
27.6.4.4. 构建定制内核
标准的 FreeBSD 内核基于名为 GENERIC 的 内核配置文件。GENERIC 内核包含了最常用的设备驱动程序和选项。有时,为了适应特定需求,构建定制内核是有用的或必要的,可以添加或删除设备驱动程序或选项。
例如,开发小型嵌入式计算机的人员,若 RAM 严重受限,可以删除不需要的设备驱动程序或选项,使内核稍微小一些。
内核配置文件位于 /usr/src/sys/arch/conf/ 目录中,其中 arch 是 uname -m 命令的输出。在大多数计算机上,arch 为 amd64,因此配置文件目录为 /usr/src/sys/amd64/conf/。
技巧
可以删除或重新创建 /usr/src,因此最好将定制内核配置文件保存在单独的目录中,例如 /root。将内核配置文件链接到 conf 目录。如果该目录被删除或覆盖,可以将内核配置文件重新链接到新目录中。
可以通过复制 GENERIC 配置文件来创建自定义配置文件。例如,假设新的定制内核是用于存储服务器,因此命名为 STORAGESERVER:
然后编辑 /root/STORAGESERVER,根据 config(5) 添加或删除设备或选项。
通过在命令行中设置 KERNCONF 来构建定制内核:
27.6.5. 安装编译后的代码
完成 buildworld 和 buildkernel 步骤后,安装新的内核和世界:
如果构建了定制内核,则必须设置 KERNCONF 以使用新的定制内核:
27.6.6. 完成更新
几个最终任务可完成整个更新过程:修改过的配置文件需要与新版本合并,需要定位并删除过时的库,然后重新启动系统。
27.6.6.1. 使用 etcupdate(8) 合并配置文件
etcupdate(8) 是用于管理文件更新的工具,这些文件不作为 installworld 的一部分更新,例如位于 /etc/ 目录中的文件。它通过对这些文件执行三方合并,将对文件所做的更改与本地版本比对。etcupdate(8) 旨在最小化用户干预。
注意
一般情况下,etcupdate(8) 不需要任何特定的参数来完成任务。然而,有一个方便的中间命令可以用于在首次使用 etcupdate(8) 时做健康检查:
此命令能让用户审计配置更改。
如果 etcupdate(8) 无法自动合并某个文件,则可以通过手动交互解决合并冲突,运行以下命令:
警告
从 mergemaster(8) 切换到 etcupdate(8) 时,首次运行可能会错误地合并更改,生成虚假的冲突。为防止这种情况,在更新源代码并构建新世界之前,执行以下步骤:
① 引导 /etc 文件的数据库;更多信息,请参见 etcupdate(8)。
② 在引导后检查差异。删除任何不再需要的本地更改,以减少未来更新时的冲突可能性。
27.6.6.2. 检查过时的文件和库
更新后,可能会有一些过时的文件或目录残留。这些文件可以通过以下命令定位:
并删除:
一些过时的库也可能残留,可以通过以下命令检测:
并通过以下命令删除:
仍然使用这些旧库的程序将在库删除后停止工作。删除旧库后,必须重新编译或替换这些程序。
技巧
当确认所有旧文件或目录可以安全删除时,通过设置
BATCH_DELETE_OLD_FILES参数,可以避免按下y并按Enter键删除每个文件。例如:
27.6.6.3. 更新后重启
更新的最后一步是重新启动计算机,以使所有更改生效:
最后更新于