19.4. 重新编译 “world”

只要您根据一定版本的 FreeBSD (FreeBSD-STABLE、FreeBSD-CURRENT 等等), 已经同步了您本地的源码树,那么您就可以使用这些源码树来重建系统。

做好备份无需强调在行动 之前 备份整个系统是多么的重要。 尽管重新编译系统是 (如果您按照文档的指示做的话) 一件很容易完成的工作, 但出错也是在所难免的, 另外, 别人在源码里面引入的错误也可能造成系统无法引导。

请确信自己已经做过备份, 并且在手边有恢复软盘或可以引导的光盘。 您可能永远也不会用到它, 但安全第一嘛!

订阅恰当的邮件列表FreeBSD-STABLE 和 FreeBSD-CURRENT 分支自然是 发展中的。为 FreeBSD 做贡献的都是人,偶尔也会犯错误。

有时这些错误没什么危害,只是引起您的系统生成新的诊断警告。 有时是灾难性的,并导致您的系统不能惊动启动或破坏您的文件系统 (甚至更糟)。

如果出现了类似的问题, 贴一封“小心(heads up)”帖到相关的邮件列表里, 讲清问题的本质以及受影响的系统。在问题解决后,再贴封“解除(all clear)”声明。

如可您想跟踪 FreeBSD-STABLE 或 FreeBSD-CURRENT 而又不阅读 FreeBSD-STABLE 邮件列表FreeBSD-CURRENT 邮件列表 各自的邮件列表,那么您是自找麻烦。

不要使用 make world许多较早的文档推荐使用 make world 来完成这项工作。 这样做会跳过一些必要的步骤, 因此只有在您知道自己在做什么的时候才可以这样做。 几乎所有的情况下 make world 都是不应该做的事情, 您应该使用这里描述的方法。

19.4.1. 更新系统的规范途径

要更新系统,就要使用下面的过程:

# make buildworld
# make buildkernel
# make installkernel
# reboot

您应该启动到单用户模式下(例如从启动提示符处使用 boot -s)。然后执行:

# mergemaster -p
# make installworld
# mergemaster
# reboot

阅读进一步的说明上边描述的序列只是有助于您开始工作的简要。 要清楚的理解每一不步,尤其是您想使用定制内核配置, 您就应阅读下面的部分。

19.4.2. 阅读 /usr/src/UPDATING

在您做其它事之前,请阅读 /usr/src/UPDATING (或在您的源码里的等效的文件)。 这个文件要包含有关于您可能遇到的问题的重要信息, 或指定了您可能使用到的命令的执行顺序。如果 UPDATING 与您这里读到相矛盾,那就先依据 UPDATING

Important: 正如先前所述,阅读 UPDATING 并不能替代订阅正确的邮件列表。两都是互补的,并不彼此排斥。

19.4.3. 检查 /etc/make.conf

检查 /usr/share/examples/etc/make.conf (在 FreeBSD   4.X 中叫做 /etc/defaults/make.conf) 以及 /etc/make.conf。 第一个文件包含了一些默认的定义 - 它们中的绝大多数都注释掉了。 为了在重新编译系统时能够使用它们, 请把这些选项加入到 /etc/make.conf。 请注意在 /etc/make.conf 中的任何设置同时也会影响每次运行 make 的结果, 因此设置一些适合自己系统的选项是一个好习惯。

一般的用户通常会从 /usr/share/examples/etc/make.conf (或者 FreeBSD 4.X 中的 /etc/defaults/make.conf) 复制 CFLAGSNOPROFILE 这样的设置到 /etc/make.conf 中并令它们生效。

请考虑其他的一些选项 (例如 COPTFLAGSNOPORTDOCS 等等), 看看是否合用。

19.4.4. 更新 /etc 里边的文件

/etc 目录包含有除了您的系统启动时执行的脚本外大部分的系统配置信息。 有些脚本随 FreeBSD 的版本而不同。

有些配置文件在天天运行的系统里也是要使用到的。尤其是 /etc/group

偶尔,某些“make installworld”的安装需要特定的用户名或用户组存在。 在升级时,有可能这些用户或组就不存在。这会在升级过程造成出错。 有时,“make installworld”会首先检查这些用户或组是否存在。

最近就有个这样的例子,当时 smmsp 用户是被增加了的。当 mtree(8) 试着建立 /var/spool/clientmqueue 时,安装过程失败了。

解决办法是检查 /usr/src/etc/group 并把它的组列表与您的进行比较。如果在新文件里有而您的文件里没有的, 就把它们复制过来。同样地,您把 /etc/group 里的任何这样的组进行更名---与 /usr/src/etc/group 中有相同 GID,但不同名的那些。

自 4.6-RELEASE 开始,您可以通过 -p 选项以预建 (pre-buildworld) 模式运行 mergemaster(8)。 这样只是比较那些对于成功执行 buildworldinstallworld 起关键作用的文件。 在第一次时,如果早期的 mergemaster 版本不支持 -p 的话,就使用源码树中的新版本:

# cd /usr/src/usr.sbin/mergemaster
# ./mergemaster.sh -p

Tip: 如果您是个偏执狂 (paranoid), 您可以检查您的系统看看哪个文件属于您已更名或删除了的那个组。

# find / -group GID -print

将显示所有 GID 组 (可以是组名也可以是数字地组 ID)所有的文件。

19.4.5. 改为单用户模式

您可能相在单用户模式下编译系统。 除了对更快处理事情显然有好处外,重装系统将接触许多重要的系统文件, 包括所有标准系统二进制文件、库文件、包含 (include) 文件等等。在运行的系统里(尤其是同时系统里有激活的用户) 更改这些文件是自寻烦恼。

另一种模式是在多用户模式下编译系统,然后转换到单用户模式下安装。 如果您喜欢这种方式,只需在建立 (build) 完成后才执行下边的步骤。 您推迟转换到单用户模式下直到您必须 installkernelinstallworld

从运行的系统里,以超级用户方式执行:

# shutdown now

这样就会转换到单用户模式。

另外也可以,重启系统,在启动提示符处,输入 -s 标识。系统就会启动单用户。再在 shell 提示符处执行:

# fsck -p
# mount -u /
# mount -a -t ufs
# swapon -a

这会检查文件系统,重新装载 / 为读/写,参考 /etc/fstab 装载其它所有的 UFS 文件系统,然后打开交换 (swapping) 开关。

Note: 如果您的 CMOS 时钟是设置为本地时间,而不是 GMT (如果 date(1) 命令输出不能显示正确的时间和地区也有确有其事), 您可能也需要执行下边的命令:

# adjkerntz -i

这样可以确定您正确的本地时区设置--不这样做, 您以后可能会碰到一些问题。

19.4.6. 删除 /usr/obj

在重建部分系统时,它们被(默认地)放到了 /usr/obj 目录下边。这些目录影射到了 /usr/src 下边。

删除这个目录,您可以加快“make buildworld”的过程, 并且省下与依赖关系有关的许多头痛的事情。

/usr/obj 下的有些文件可能设置了不可改 (immutable) 属性(查看 chflags(1) 了解更多), 您必须先把这些标志去掉。

# cd /usr/obj
# chflags -R noschg *
# rm -rf *

19.4.7. 重编译源码

19.4.7.1. 保存输出

建议把执行 make(1) 后得到的输出存成一个文件。 如果什么地方出了错,您就会有个错误信息的备份。 尽管这样不能帮您分析哪里出了错, 但如果您把您的问题贴到某个邮件列表里就能帮助其他的人。

这样做最简单的办法是使用 script(1) 命令,同是带上参数指定存放输出的文件名。 您应在重建系统之前立即这样做,然后在过程完成时输入 exit

# script /var/tmp/mw.out
Script started, output file is /var/tmp/mw.out
# make TARGET
... compile, compile, compile ...
# exit
Script done, ...

如果您这样做,就 不要 把文件存到 /tmp 里边。下次启动时,这个目录就会被清除掉。 存放的最好地方是 /var/tmp (如上个实例)或 root 的主目录。

19.4.7.2. 编译基本系统

您必须在/usr/src目录里边:

# cd /usr/src

(当然,除非您的源码是在其它地方,真是这样的话更换成那个目录就行了)。

使用 make(1) 命令重建系统。这个命令会从 Makefile (描述组成 FreeBSD 的程序应该怎样被重建, 以什么样的顺序建立等等) 里读取指令。

输入的一般命令格式如下:

# make -x -DVARIABLE target

这个例子里,-x 是会传递给 make(1) 的一个选项。查看 make(1) 手册有您可用的选项例子。

-DVARIABLE 传递一个变量给 Makefile。这些变量控制了 Makefile 的行为。这些同 /etc/make.conf 设置的变量一样, 只是提供了另一种设置它们的方法。

# make -DNOPROFILE target

是另一种指定不被建立 (built) 的先定库 (profiled libraries) 的方式,协同 /etc/make.conf 里的

NOPROFILE=    true     #    避免编译先定库

一起使用。

目标 (target) 告诉 make(1) 什么该做。每个 Makefile 定义了一定数量不同的“目标 (targets)”, 然后您选择的目标就决定了什么会发生。

有些目标列在 Makefile 里的,但并不意味着您要执行。相反,建立过程 (build process) 利用它们把重建系统的一些必要的步骤分割成几个子步骤。

大部分的时间不需要向 make(1) 传递参数,因此您的命令看起来可能象这样:

# make target

从 FreeBSD 的 2.2.5 版本开始 (实际上,是先在 FreeBSD-CURRENT 分支里第一次创建,然后在 FreeBSD-STABLE 的 2.2.2 和 2.2.5 两个版本间,进行了大翻新),world target 已经分成了两个部分:buildworldinstallworld。 从 FreeBSD 的 5.3 版开始, world target 在默认时已经改为完全不动作, 因为它事实上对于许多用户都具有相当的危险性。

正如名字所暗示的,buildworld/usr/obj 下边建立了一个全新的树,然后 installworld 就在当前的机器里安装这个树。

因为两个原因,这点很有用。首先,它允许您安全地完成建立 (build),而没有您运行的系统组成部分的影响。建立 (build) 是“自主的 (self hosted)”。因为这样, 您可以安全地在以多用户模式运行的机器里执行 buildworld ,而不用当心不良影响。 但是依然推荐您在单用户模式时运行 installworld

第二,允许您使用 NFS 装载 (NFS mounts) 升级您网络里的多台计算机。如果您有三台 ABC 想进行升级,在A 执行 make buildworldmake installworld。然后从 A NFS 装载 (NFS mount) BC/usr/src/usr/obj,接着您就执行 make installworldBC 上安装建立 (build) 的结果。

尽管 world target 仍然存在,强烈建议您不要用它。

运行

# make buildworld

现在可能给 make 指定 -j 选项了,这样会使用产生出几个并发的进程来。 这在多处理器 (multi-CPU) 机器里最有用。但是, 由于大部分的编译过程是 IO 限制远胜 CPU 限制,它在单处理器 (single-CPU) 的机器里也是有用的。

在一般的单 CPU 机器里,您要运行:

# make -j4 buildworld

make(1) 然后会有至多 4 个进程在同一时刻执行。 贴到邮件列表里的实验证据显示这样会收到最好的效果。

如果您有一台多 CPU 机器,那您就使用 SMP 配置内核,试试 6 到 10 之间的值,看这些值提速如何。

注意,这仍处在实验性阶段,如果提交到源码树上的话, 可能会断送其前程 (break this feature)。 如果用这个参数编译的话,您报告错误前试试不用它。

19.4.7.3. 耗时

有许多因素影响 build 时间,但通常一台带有 128 MB 内存 500 MHz 的 Pentium® III 要花费大约 2  小时来 build FreeBSD-STABLE 树,并且在整个过程中不带什么技巧或捷径。 FreeBSD-CURRENT 树花的时间还要更长一点。

19.4.8. 编译和安装新内核

要充分利用您的新系统,您应该重新编译内核。 这是很有必要的,因为特定的内存结构已经发生了改变,像 ps(1)top(1) 这样的程序会不能工作, 除非内核同源码树的版本是一样的。

最简单、最安全的方式是 build 并安装一个基于 GENERIC 的内核。虽然 GENERIC 可能没有适合您的系统的所有必要的设备, 但它包括了启动您的系统到单用户模式所必需的内容。 这是个不错的检测新系统是否工作正常的测试。在从 GENERIC 启动、核实系统可以工作后, 您就可以建立 (build) 一个基于您的正常内核配置文件的新的内核了。

在新的 FreeBSD 版本中,首先完成 build world 然后再编译新内核非常重要。

Note: 如果您想建立一个定制内核,而且已经有了配置文件, 只需象这样使用 KERNCONF=MYKERNEL

# cd /usr/src
# make buildkernel KERNCONF=MYKERNEL
# make installkernel KERNCONF=MYKERNEL

在 FreeBSD 4.2 或更早的版本里,您必须使用 KERNEL= 替换 KERNCONF=。在 2001 年 2 月 2 号以前发行的 4.2-STABLE 并不识别 KERNCONF=

注意,如果您已把 内核安全级别(kern.securelevel) 调高到了 1 以上,而且还设置了 noschg 或相似的标识到了您的内核二进制里边,您可能会发现转换到单用户模式里使用 installkernel 是很有必要的。 另外您应该也能毫无问题地从多用户模式执行这两个命令。查看 init(8) 了解更多关于 内核安全级(kern.securelevel) 的信息;查看 chflags(1) 了解更多关于不同文件标识的信息。

如果您升级到 FreeBSD 4.0 以前版本,您应旧的内核 build 程序。但还是推荐您使用新版的 config(8), 可以使用下边的命令行:

# /usr/obj/usr/src/usr.sbin/config/config KERNELNAME

19.4.9. 重启到单用户模式

您应该单用户模式测试新内核。照Section 19.4.5处的说明去做。

19.4.10. 安装新的系统二进制(System Binaries)

如果您正建立一个足以使用 make buildworld 的 FreeBSD 版本,那么您现在应该使用 installworld 来安装新的系统二进制。

执行

# cd /usr/src
# make installworld

Note: 如果在 make buildworld 的命令行指定了变量,您就必须在 make installworld 命令行里指定同样的变量。 对于其它的选项也不是必需的,如,-j 就不能同 installworld 一起使用。

举例,您执行了:

# make -DNOPROFILE buildworld

您就必须使用:

# make -DNOPROFILE installworld

来安装结果,否则就要试着安装先定 (profiled) 的在 make buildworld 阶段没有建立 (built) 的二进制文件。

19.4.11. 不是由 make installworld 更新的更新文件

重新编译整个系统不会使用新的或改过的配置文件更新某些目录 (尤其像 /etc/var/usr)

更新这些文件最简单的方式就是使用 mergemaster(8),手工去做也是可以的,只要您愿意。 不管您选择哪一种,一定记得备份 /etc 以防出错。

19.4.11.1. mergemaster

贡献者:Tom Rhodes.

mergemaster(8) 工具是个有针对性的脚本 (Bourne script),用于检测 /etc/usr/src/etc 源码树里边的配置文件的不同点。 这是保持系统配置文件同源码树里的一起更新的推荐方式。

mergemaster 被集成到了 3.3-RELEASE 和 3.4-RELEASE 之间的 FreeBSD 基本系统里,这意味着自 3.3 版本起所有的 -STABLE 和 -CURRENT 系统都有。

在提示符里简单地输入 mergemaster 就可以开始,并观看它的开始过程。mergemaster 会建立一个临时的根(root)环境,在 / 下, 放置各种系统配置文件。这些文件然后同当前安装到您系统里的进行比较。 此时,不同的文件会以 diff(1) 格式进行显示,使用 + 符号标识增加或修改的行,- 标识将完全删除的行或将被替换成新行。查看 diff(1) 手册可以得到更多关于 diff(1) 语法和文件不同点怎样显示的信息。

mergemaster(8) 会给您显示每个文件的不同处, 这样您就可以选择是删除新文件 (相对临时文件), 是以未改状态安装临时文件,是以当前安装的文件合并临时文件, 还是再看一次 diff(1) 结果。

“选择删除临时文件”将使 mergemaster(8) 知道我们希望保留我们当前的文件不改,并删除新的。 并不推荐这个选择,除非您没有更改当前文件的理由。任何时候在 mergemaster(8) 提示符里输入 ?,您就会得到帮助。 如果选择跳过文件,在其它文件处理完后再次进行。

“选择安装未修改临时文件”将会使新文件替换当前的。 对大部分未改的文件,这是个最好的选择。

“选择合并文件”将为您打开一个文本编辑器, 里边是两个文件的内容。您现在就可以一边合并它们, 一边在屏幕里查看,同时从两者中选取部分生成最终文件。 当两个文件一起比较时,l 键会选择左边的内容, r 会选择右边的。最终的输出是由两个部分组成的一个文件, 用它就可以安装了。这个选项通常用于用户修改了设置的文件。

“选择再次查看 diff(1) 结果”将会在提供给选择之前, 显示文件的不同处,就象 mergemaster(8) 所做的一样。

mergemaster(8) 完成了对系统文件的处理后, 您会得到其它的选项。mergemaster(8) 可能会问您是否要重建密码文件, 如果您的 FreeBSD 版本超过 5.0,还会问您是否想要执行 MAKEDEV(8),最后带上一个选项删除剩下的临时文件。

19.4.11.2. 手动更新

如果想要手工更新,但不要只是从 /usr/src/etc 把文件复制到 /etc 就了事。有些文件是必须先“安装”的。 这是因为 /usr/src/etc 目录并 不是 想像的那样是 /etc 目录的一个复制。事实上,有些是文件是 /etc 有的,而 /usr/src/etc 里边没有。

如果您使用 mergemaster(8) (作为推荐),您可以向前跳到下一节

手工做最简单的方式是安装这些文件到一个新的目录,完成后再来查找不同处。

备份您已有的 /etc虽然,理论上,没有什么会自动访问这个目录, 事情还是做稳操胜当一点。复制已有 /etc 到一个安全的地方,如:

# cp -Rp /etc /etc.old

-R 完成递归复制 (设者注:即可以复制目录以下的所有内容),-p 保留文件的时间、所属等等。

您需要建立的个虚目录 (a dummy set of directories ) 来安装新的 /etc 和其它文件。 /var/tmp/root 是个不错的选择, 除此之外,还有一些子目录是需要的。

# mkdir /var/tmp/root
# cd /usr/src/etc
# make DESTDIR=/var/tmp/root distrib-dirs distribution

这样就建好了需要的目录结构,然后安装文件。在 /var/tmp/root 下建立的大部分子目录是空的, 而且要删除掉。最简单的方式是:

# cd /var/tmp/root
# find -d . -type d | xargs rmdir 2>/dev/null

这样会删除所有的空目录。(标准的错误信息被重定向到了 /dev/null,以防止关于非空目录的警告。

/var/tmp/root 现在包含了应放在 / 下某个位置的所有文件。 您现在必须仔细检查每一个文件,检测它们与您已有的文件有多大不同。

注意,有些已经安装在 /var/tmp/root 下的文件有个“.”在开头。在写的时候,像这样唯一的文件是 /var/tmp/root//var/tmp/root/root/ 里 shell 启动文件,尽管可能有其它的(依赖于您什么时候读取这个)。 确信使用 ls -a 可以看到它们。

最简单的方式是使用 diff(1) 去比较两个文件:

# diff /etc/shells /var/tmp/root/etc/shells

这会显示出 /etc/shells 文件和新的 /var/tmp/root/etc/shells 文件的不同处。 用这些来决定是合并您已做的变化还是复制您的旧文件过来。

使用日戳 (Time Stamp) 命名新的 Root(根)目录(/var/tmp/root),这样您可以轻松地比较两个版本的不同: 频繁重建系统意味着必须频繁更新 /etc,而这可能会有点烦琐。

在合并到 /etc 的文件里, 最新更改的您可以做个复制,由此加快这个(指更新)过程。 下边就给出了一个怎样做的主意。

  1. 像平常一样建立系统 (Make the world)。当您想更新 /etc 和其它目录里, 给目标目录一个含有当前日期的名字。假如您是 1998 年 2 月 14 日做的,您可以执行下边的:

    # mkdir /var/tmp/root-19980214
    # cd /usr/src/etc
    # make DESTDIR=/var/tmp/root-19980214 \
        distrib-dirs distribution
    
  2. 如上边列出的,从这个目录合并变化。

    在您完成后,不要 删除 /var/tmp/root-19980214 目录。

  3. 在您下载了最新版的源码并改过后,执行第一步。 这样将得到一个新的目录,可能叫做 /var/tmp/root-19980221 (如果等了一周做的升级)。

  4. 您现在能看到两个目录间的不同了---在隔周的时间里使用 diff(1) 建立递归 diff 产生的不同:

    # cd /var/tmp
    # diff -r root-19980214 root-19980221
    

    一般情况下,这两种间的不同处比 /var/tmp/root-19980221/etc/etc 之间的不同要小很多。 因为不同点更小,也就更容易把这些变化移到您的 /etc 目录里边。

  5. 您现在可以删除早先的两个 /var/tmp/root-* 目录:

    # rm -rf /var/tmp/root-19980214
    
  6. 每次您需要合并这些变化到 /etc 里,就重复这个流程。

您可以使用 date(1) 自动产生目录的名称:

# mkdir /var/tmp/root-`date "+%Y%m%d"`

19.4.12. 更新/dev

Note: 如果您正在运行 FreeBSD 5.0 或更后的版本, 您可以安全地跳过这部分。这些版本使用了 devfs(5) 来透明地分配设备结点。

许多情况下,在有必要更新设备结点时,mergemaster(8) 工具就可以实现,并且可以自动地完成。 这里的说明用于怎样手工更新设备结点。

考虑到安全,这里用的是多步流程。

  1. 复制 /var/tmp/root/dev/MAKEDEV/dev

    # cp /var/tmp/root/dev/MAKEDEV /dev
    

    如果您使用 mergemaster(8) 去更新 /etc,那么您的 MAKEDEV 脚本应该已经被更新过,虽然它不会影响检查 (使用 diff(1)), 必要时手工复制一下。

  2. 现在,给当前的 /dev 做个快照。照的时候一定要注意每个文件名的许可 (permissions)、所属(ownerships)、主从数字 (major and minor numbers), 不必包括日戳 (time stamps)。最简单的方式是使用 awk(1) 提取信息:

    # cd /dev
    # ls -l | awk '{print $1, $2, $3, $4, $5, $6, $NF}' > /var/tmp/dev.out
    
  3. 重做设备结点:

    # sh MAKEDEV all
    
  4. 这时,把这个目录的另一个快照输出到 /var/tmp/dev2.out。现在检查这两个文件, 查找任何您没建立的设备结点。就该不会很多,但是保险一点总是好的。

    # diff /var/tmp/dev.out /var/tmp/dev2.out
    

    您可能注意到磁盘分区 (disk slice) 的差别,它会使像:

    # sh MAKEDEV sd0s1
    

    那样的命令重新建立分区入口 (slice entries)。您的具体情况可能不同。

19.4.13. 更新/stand

Note: 这一步只是为了收尾,可以安全省略。如果您在使用 FreeBSD 5.2 或更新的版本,/rescue 目录会为用户进行自动更新,使用的是在 make installworld 期间静态编译地最新的二进制文件,因此也就不用废话更新 /stand 的必要性了。

为了完成,您可能想额外地更新 /stand 里的文件。这些文件由链接到 /stand/sysinstall 的二进制文件硬链接组成。这个文件要静态链接,以便没有其它文件系统时 (尤其是 /usr) 被装载时也能工作。

# cd /usr/src/release/sysinstall
# make all install

19.4.14. 重启

现在完成了。在您检查所有内容都放置正确后, 您可以重启系统了。只是简单的 shutdown(8) 可以这样做:

# shutdown -r now

19.4.15. 结束

恭喜!您现在成功升级了您的 FreeBSD 系统。

如果还有轻微的错误,可以轻易地重建系统的选定部分。 例如,在部分升级或合并 /etc 时,您不小心删除了 /etc/magicfile(1) 命令就会停止工作。这种情况下,执行下边进行修复:

# cd /usr/src/usr.bin/file
# make all install

19.4.16. 问题

19.4.16.1. 每个变化您都须要重建系统吗?
19.4.16.2. 我的编译失败,并伴随有许多 11 (或其它的数字信息) 号错误。是怎么回事呀?
19.4.16.3. 我完成后可以删除 /usr/obj 吗?
19.4.16.4. 中断的 build 可以被恢复吗?
19.4.16.5. 我怎样加快建立系统的速度?
19.4.16.6. 如果出现了错误我该怎么办?

19.4.16.1. 每个变化您都须要重建系统吗?

这个不好说,因为要看变化的情况。如,如果您刚运行了 CVSup,并得到下边更新的文件:

src/games/cribbage/instr.c
src/games/sail/pl_main.c
src/release/sysinstall/config.c
src/release/sysinstall/media.c
src/share/mk/bsd.port.mk

这就不必重建整个系统。您只需到相关的子目录里执行 make all install,仅此而已。 但是,如果有重大变化,如 src/lib/libc/stdlib, 那么您就要重建系统或至少静态链接的那些部分 (除了您增加的部分都是静态链接的)。

在这天后,就是您的事了。要是说每两个星期重建一下系统的话, 您可能会高兴。或者您可能只想重做改变过的部分, 确信您能找出所有依赖关系。

当然,所有这些依赖于您想升级的频率,和您是否想跟踪 FreeBSD-STABLE 或 FreeBSD-CURRENT。

19.4.16.2. 我的编译失败,并伴随有许多 11 (或其它的数字信息) 号错误。是怎么回事呀?

这个通常表示硬件错误。 (重)建系统是个强压测试系统硬件的有效地方式, 并且常常产生内存错误。 这些正好表示它们自已做为编译器离奇地死于收到的奇怪信息。

一个确信的指示器是如果重新开始 make,并且整个过程中会死在不同的点上。

对于这种情况,您没有什么可做的,除了更换机器里的部件,看是哪一个坏了。

19.4.16.3. 我完成后可以删除 /usr/obj 吗?

简短地说,可以。

/usr/obj 包含了所有在编译阶段生成的目标文件。通常, 在“make buildworld”过程中第一步之一就是删除这个目录重新开始。 这种情况下,在您完成后,保留 /usr/obj 没有多大意义,还可释放一大堆磁盘空间(通常在 340 MB 左右)。

只是,如果您清楚您在干什么,您可以让“make buildworld”跳过这一步。 这会让后继的 build 执行得更快,因为大部分的源码都不必再进行编译了。 这个的另一面就在于敏感的依赖问题可以潜在, 并以奇怪的方式引起 build 的失败。这在 FreeBSD 邮件列表里经常引起沸腾, 当有人抱怨他们 build 失败时,并没意识到这是因为自已是想抄近路 (意思是说少了些必要的步骤)。

19.4.16.4. 中断的 build 可以被恢复吗?

依赖于您在您找到问题之前整个过程进行了多远。

大体上 (这个并不是硬性规定), “make buildworld”过程会建立新版的基本工具 (如 gcc(1)make(1)) 以及系统二进制文件。 这些工具和二进制文件然后被安装。新的工具和库然后用来重建它们自已, 并再次被安装。整个系统 (现在包括了常规的用户程序,如 ls(1)grep(1)) 然后使用新的系统文件被重建。

如果您处在最后阶段,您就知道了 (因为您已经看过您存储的输出),然后您可以做(相当安全):

... 问题修复 ...
# cd /usr/src
# make -DNOCLEAN all

这将不能取消 “make buildworld”先前所做的工作。

在“make buildworld”的输出中如果看到如下信息:

--------------------------------------------------------------
Building everything..
--------------------------------------------------------------

那么这样做就是相当安全的。

如果您没有看到那个信息,或者您不能确定,那么安全第一,从头开始。

19.4.16.5. 我怎样加快建立系统的速度?

  • 以单用户模式运行

  • /usr/src/usr/obj 目录放到不同磁盘里的独立文件系统里。如果可能,这些磁盘在不同的磁盘控制器里。

  • 更好的,是把这些文件系统放置到多个使用 ccd(4) (连接磁盘驱动器--concatenated disk driver)设备的磁盘里。

  • 关掉 profiling (在 /etc/make.conf 里设置 “NOPROFILE=true”)。您差不多用不了它。

  • /etc/make.conf 里也为 CFLAGS 设置上 -O -pipe。 最佳优化 -O2 会更慢,而且 -O-O2 之间的优化差别基本上可以忽略。 -pipe 让编译器使用管道而不用临时文件进行通信, 这样可以减少磁盘存取 (以内存作为代价)。

  • 传递 -jn 选项给 make(1) 以便并发运行多个进程。 这样就不会考虑您的是否是单个或多个处理器机器。

  • 存放 /usr/src 的文件系统可以使用 noatime 选项被装载(或再装载)。 这样会防止文件系统记录文件的存取时间。您可能并不需要这些信息。

    # mount -u -o noatime /usr/src
    

    Warning这个例子里假定 /usr/src 是在它自已的文件系统里。如果不是 (例如假设它是 /usr 的部分),那么您就需要那个文件系统装载点, 而不是 /usr/src

  • 存放 /usr/obj 的文件系统可以使用 async 选项被装载(或被再装载)。 这会引起异步写盘。换句话说,写是立即完成了, 而数据要延迟几秒才会写到盘里。这就允许写到一堆, 如此产生戏剧性的性能提高。

    Warning记住,这个选项会使您的文件系统更加脆弱。 使用这个选项增大了这样一个机率:要是电源断了, 在机器重启后,文件系统将处在不可恢复状态。

    如果在这个文件系统里 /usr/obj 是很关键的,这不是问题。如果您有其它有价值的数据在同一个文件系统, 那么在您使用这个选项这前,确认备份一下。

    # mount -u -o async /usr/obj
    

    Warning同上,如果 /usr/obj 不在自已的文件系统里,使用相关装载点的名字把它从例子里边替换掉。

19.4.16.6. 如果出现了错误我该怎么办?

绝对确信您的环境没有先前 build 留下的残余。这点够简单。

# chflags -R noschg /usr/obj/usr
# rm -rf /usr/obj/usr
# cd /usr/src
# make cleandir
# make cleandir

不错,make cleandir 真的要执行两次。

然后重新开始整个过程,使用 make buildworld 开始。

如果您还有问题,就把错误和 uname -a 的输出发送到 FreeBSD 一般问题邮件列表 邮件列表。准备回答其它关于您的设置的问题!