24.6.从源代码更新 FreeBSD

与二进制更新相比,通过从源代码编译来更新FreeBSD具有一些优势。代码可以用选项来构建,以利用特定的硬件。基本系统的某些部分可以用非默认的设置来构建,或者在不需要或不需要的地方完全不做。与安装二进制更新相比,编译过程需要更长的时间来更新系统,但允许完全定制,以产生一个定制的FreeBSD版本。

24.6.1. 快速启动

这是对通过从源代码构建来更新 FreeBSD 的典型步骤的快速参考。后面的章节会更详细地描述这个过程。

更新和建设

# git pull /usr/src  ①
check /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/ 中所需要的配置文件。

⑧ 转到源目录。

⑨ 安装世界。

⑩ 更新和合并/etc/中的配置文件。

⑪ 重新启动系统以使用新建立的世界和内核。

24.6.2. 为源码更新做准备

阅读 /usr/src/UPDATING。在更新之前或之后必须执行的任何手动步骤都在这个文件中描述。

24.6.3. 更新来源

FreeBSD 的源代码位于 /usr/src/。更新这个源代码的首选方法是通过 Git 版本控制系统。验证源代码是否在版本控制之下。

# cd /usr/src
# git remote --v
origin  https://git.freebsd.org/src.git (fetch)
origin  https://git.freebsd.org/src.git (push)

这表明 /usr/src/ 处于版本控制之下,可以用 git(1)open in new window 更新。

# git pull /usr/src

如果目录最近没有被更新,更新过程可能需要一些时间。在它完成后,源代码是最新的,下一节所述的构建过程可以开始。

备注

获得来源。

如果输出显示fatal: not a git repository,说明那里的文件缺失或用不同的方法安装。需要重新签出该源。

表1. FreeBSD 版本和存储库的分支

uname -r Output存储库路径描述
*X.Y*-RELEASEreleng/*X.Y*发布版只加上关键的安全和错误修复补丁。建议大多数用户使用这个分支。
*X.Y*-STABLEstable/*X*发布版加上该分支上的所有额外开发。STABLE 指的是应用程序二进制接口(ABI)没有改变, 因此为早期版本编译的软件仍然可以运行。例如,在FreeBSD 10.1上编译的软件仍然可以在后来编译的FreeBSD 10-STABLE上运行。STABLE分支偶尔会有可能影响用户的错误或不兼容,尽管这些通常会很快被修复。
*X*-CURRENTmain最新的未发布的 FreeBSD 开发版本。CURRENT 分支可能会有重大的错误或不兼容,因此只推荐给高级用户。

uname(1)open in new window 确定正在使用哪个版本的 FreeBSD。

# uname -r
10.3-RELEASE

根据 FreeBSD 版本和版本库分支,用于更新 10.3-RELEASE 的源代码的版本库路径是 releng/10.3。这个路径在签出源代码时被使用。

# mv /usr/src /usr/src.bak ①
# git clone --branch releng/10.3 https://git.FreeBSD.org/src.git /usr/src ②

① 把旧的目录移开。如果这个目录中没有本地的修改,就可以删除它。

② FreeBSD 版本和版本库分支的路径会被添加到版本库的 URL 中。第三个参数是本地系统上源代码的目标目录。

24.6.4. 从源头开始建设

世界,或者说除了内核以外的所有操作系统,都被编译了。这样做首先是为了提供最新的工具来构建内核。然后是内核本身的构建。

# cd /usr/src
# make buildworld
# make buildkernel

编译后的代码被写到 /usr/obj

这些是基本步骤。下面将介绍控制构建的其他选项。

24.6.4.1. 执行清洁构建

某些版本的 FreeBSD 联编系统会将先前编译的代码留在临时对象目录 /usr/obj 中。这可以通过避免重新编译没有变化的代码来加快以后的联编速度。要强制重建所有内容,可以在开始联编前使用 cleanworld。

# make cleanworld

24.6.4.2. 设置工作的数量

在多核处理器上增加构建作业的数量可以提高构建速度。用 sysctl hw.ncpu 来确定核的数量。处理器各不相同,不同版本的 FreeBSD 所使用的联编系统也各不相同,因此测试是唯一可以确定不同数量的作业对联编速度有何影响的方法。作为一个起点,可以考虑核数的一半到两倍之间的数值。作业的数量是用-j指定的。

例1. 增加建设工作的数量

用四项工作建设世界和内核。

# make -j4 buildworld buildkernel

24.6.4.3. 只构建内核

如果源代码有变化,必须完成buildworld。之后,可以在任何时候运行buildkernel来构建内核。要想只构建内核

# cd /usr/src
# make buildkernel

24.6.4.4. 构建一个自定义的内核

标准的 FreeBSD 内核是基于一个叫做 GENERIC 的内核配置文件。GENERIC 内核包括最常用的设备驱动和选项。有时,建立一个定制的内核是有用的或必要的,可以添加或删除设备驱动程序或选项以适应特定的需要。

例如,有人在开发一台内存严重受限的小型嵌入式计算机时,可以删除不需要的设备驱动程序或选项,使内核略微缩小。

内核配置文件位于 /usr/src/sys/arch/conf/,其中 arch 是 uname -m 的输出。在大多数计算机上,它是 amd64,给出的配置文件目录是 /usr/src/sys/amd64/conf/

技巧

/usr/src 可以被删除或重新创建,所以最好把定制的内核配置文件放在一个单独的目录下,比如 /root。将内核配置文件链接到 conf 目录中。如果该目录被删除或覆盖,内核配置文件可以被重新链接到新目录中。

# cp /usr/src/sys/amd64/conf/GENERIC /root/STORAGESERVER
# cd /usr/src/sys/amd64/conf
# ln -s /root/STORAGESERVER .

然后编辑 /root/STORAGESERVER,添加或删除设备或选项,如config(5)open in new window所示。

定制的内核是通过在命令行上设置 KERNCONF 到内核配置文件来建立的。

# make buildkernel KERNCONF=STORAGESERVER

24.6.5. 安装已编译的代码

在 buildworld 和 buildkernel 的步骤完成后,新的内核和世界被安装。

# cd /usr/src
# make installkernel
# shutdown -r now
# cd /usr/src
# make installworld
# shutdown -r now

如果建立了自定义内核,KERNCONF也必须被设置为使用新的自定义内核。

# cd /usr/src
# make installkernel KERNCONF=STORAGESERVER
# shutdown -r now
# cd /usr/src
# make installworld
# shutdown -r now

24.6.6. 完成更新

最后几项任务完成了更新。任何修改过的配置文件都将与新版本合并,过时的库被定位并删除,然后系统被重新启动。

24.6.6.1. 用 etcupdate(8)open in new window 合并配置文件

etcupdate(8)open in new window 是一个管理更新文件的工具,这些文件没有作为安装世界的一部分被更新,比如位于 /etc/ 的文件。它通过对这些文件的修改与本地版本进行三方合并来管理更新。与 mergemaster(8)open in new window 的交互式提示相比,它还被设计为尽量减少用户的干预。

备注

一般来说,etcupdate(8)open in new window在工作中不需要任何特殊的参数。然而,有一个很方便的中间命令,用于检查第一次使用 etcupdate(8)open in new window 时将会做什么。

# etcupdate diff

该命令允许用户审计配置的变化。

如果 etetcupdate(8)open in new window不能自动合并文件,可以通过发布手动交互来解决合并冲突。

# etcupdate resolve

警告

当从 mergemaster(8)open in new window切换到 etcupdate(8)open in new window时,第一次运行可能会不正确地合并变化,产生虚假的冲突。为了防止这种情况,在更新源代码和构建新的世界之前,请执行以下步骤。

# etcupdate extract ①
# etcupdate diff ②

① 启动库存/etc文件的数据库,更多信息见etcupdate(8)。

② 在启动后检查差异。修剪任何不再需要的本地修改,以减少在未来更新中发生冲突的机会。

24.6.6.2. 用 mergemaster(8)open in new window 合并配置文件

mergemaster(8)open in new window 提供了一种将对系统配置文件的修改与这些文件的新版本进行合并的方法。 mergemaster(8) 是首选的 etcupdate(8)open in new window 的替代方法。 使用 -Ui,mergemaster(8) 自动更新未被用户修改的文件,并安装尚未存在的新文件。

# mergemaster -Ui

如果一个文件必须被手动合并,一个交互式的显示允许用户选择文件的哪些部分被保留。参见 mergemaster(8)open in new window以了解更多信息。

24.6.6.3. 检查是否有过期的文件和库

一些过时的文件或目录在更新后可能仍然存在。这些文件可以被找到。

# make check-old

并删除。

# make delete-old

一些过时的库也可能保留下来。这些可以用以下方法检测。

# make check-old-libs

并删除了与

# make delete-old-libs

当库被删除后,仍然使用这些旧库的程序将停止工作。这些程序必须在删除旧库后重建或替换。

技巧

当知道所有的旧文件或目录都可以安全删除时,可以通过在命令中设置BATCH_DELETE_OLD_FILES来避免按y和回车键来删除每个文件。比如说。

# make BATCH_DELETE_OLD_FILES=yes delete-old-libs

24.6.6.4. 更新后重新启动

更新后的最后一步是重新启动计算机,以便所有的变化都生效。

# shutdown -r now