21.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 都是不应该做的事情, 您应该使用这里描述的方法。

21.4.1 更新系统的规范途径

  要更新系统, 就一定要首先查看 /usr/src/UPDATING 文件, 以了解 buildworld 之前需要完成的步骤, 然后使用下面的过程:

# make buildworld
# make buildkernel
# make installkernel
# reboot

注意: 有时, 可能需要额外地执行一次 mergemaster -p 才能够完成 buildworld 步骤。 这些要求, 会在 UPDATING 中进行描述。 一般而言, 您可以简单地跳过这一步, 只要进行的不是大跨度的 FreeBSD 版本升级。

  在 installkernel 成功完成之后, 您需要引导到单用户模式 (举例而言, 可以在加载器提示后输入 boot -s)。 接下来执行:

# mergemaster -p
# make installworld
# mergemaster
# reboot

阅读进一步的说明: 前面所给出的, 只是帮助您开始工作的简要说明。 要清楚地理解每一步, 特别是如果打算自行定制内核配置, 就应阅读下面的内容。

21.4.2 阅读 /usr/src/UPDATING

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

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

21.4.3 检查 /etc/make.conf

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

  一般的用户通常会从 /usr/share/examples/etc/make.conf 复制 CFLAGSNO_PROFILE 这样的设置到 /etc/make.conf 中并令它们生效。

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

21.4.4 更新 /etc 里边的文件

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

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

  偶尔, 作为安装过程的一部分, make installworld 会要求事先创建某些特定的用户或组。 在进行升级时, 它们可能并不存在。 这会给升级造成问题。 有时, make buildworld 会检查它们是否已经存在。

  最近就有个这样的例子,当时 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

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

# find / -group GID -print

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

21.4.5 改为单用户模式

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

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

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

# shutdown now

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

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

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

  这会检查文件系统,重新将 / 以读/写模式挂接, 参考 /etc/fstab 挂接其它所有的 UFS 文件系统,然后启用交换区。

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

# adjkerntz -i

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

21.4.6 删除 /usr/obj

  随着重新构建系统的进行, 编译结果会放到 (默认情况下) /usr/obj 下。 这些目录会映射到 /usr/src

  通过删除这个目录, 可以加速 make buildworld 的过程, 并避免相互依赖关系等复杂的问题。

  /usr/obj 中的某些文件可能设置了不可改标记 (详情参见 chflags(1)), 需要首先去掉这些标志。

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

21.4.7 重编译源码

21.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 的主目录。

21.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 -DNO_PROFILE target

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

NO_PROFILE=    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

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

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

  第二,允许您使用 NFS 挂接 (NFS mounts) 升级您网络里的多台计算机。如果您有三台 ABC 想进行升级,在A 执行 make buildworldmake installworld。 然后将 A 上的 /usr/src/usr/obj 通过 NFS 挂接到 BC 上, 接下来, 只需在 BC 上使用 make installworld 来安装构建的结果就可以了。

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

  运行

# make buildworld

  目前, 我们提供了一个试验性的功能, 可以在构建过程中为 make 指定 -j 参数, 令其在构建过程中同时启动多个并发的进程。 对于多 CPU 的机器而言, 这样做有助于发挥其性能。 不过, 由于编译过程中的瓶颈主要是在 IO 而不是 CPU 上, 因此它也会对单 CPU 的机器带来好处。

  对典型的单 CPU 机器, 可以使用:

# make -j4 buildworld

  这样, make(1) 会最多同时启动 4 个进程。 从发到邮件列表中的经验看, 这样做能带来最佳的性能。

  如果您使用的机器有多颗 CPU, 并且配置了 SMP 的内核, 也可以试试看 6 到 10 的数值, 并观察是否能带来构建性能上的改善。

警告: 目前为止这仍然是试验性的功能, 提交到源代码树上的变更, 也随时可能导致这一功能不可用。 如果您使用这个参数时发现无法构建 world, 在报告问题之前, 应首先试试看去掉这个参数是否能修正问题。

当您通过源代码升级系统时, 使用这一选项可能引致无法预测的后果。

21.4.7.3 耗时

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

21.4.8 编译和安装新内核

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

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

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

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

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

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

21.4.9 重启到单用户模式

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

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

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

  执行

# cd /usr/src
# make installworld

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

举例,您执行了:

# make -DNO_PROFILE buildworld

您就必须使用:

# make -DNO_PROFILE installworld

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

21.4.11 不是由 make installworld 更新的更新文件

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

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

21.4.11.1 mergemaster

贡献者:Tom Rhodes.

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

  在提示符里简单地输入 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),最后带上一个选项删除剩下的临时文件。

21.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"`

21.4.12 更新/dev

注意: 如果您正在运行 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)。您的具体情况可能不同。

21.4.13 更新/stand

注意: 这一步应被看作最后的扫尾工作。 您可以安全地跳过这一步。 如果正在使用的是 FreeBSD 5.2 或更新的版本, /rescue 目录会为用户自动更新, 其内容是在 make installworld 过程中所生成的静态联编的可执行程序, 这就不需要更新 /stand (在 FreeBSD 6.0 和更新版本中不再存在) 了。

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

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

21.4.14 重启

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

# shutdown -r now

21.4.15 结束

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

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

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

21.4.16 问题

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

21.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。

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

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

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

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

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

简短地说,可以。

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

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

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

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

一般而言 (当然这并不是硬性规定), make buildworld 的过程中将会首先构建新版的基本构建工具 (例如 gcc(1), 以及 make(1)) 和系统库。 随后会安装这些工具和库。 这些新版本的工具和库在随后将被用于重新编译和连接它们本身。 整个系统 (现在包括了常规的用户程序, 例如 ls(1)grep(1)) 会同新版的系统文件一起被重新构建。

如果您正处于最后一个阶段, 并且了解它 (因为您已经看过了所保存的输出) 则可以 (相当安全地) 做:

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

注意: 在 FreeBSD 5.X 和更早版本中, 应使用 -DNOCLEAN 代替。

这样就不会取消先前的 make buildworld 所做的工作。

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

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

出现在 make buildworld 的输出中, 则这样做应该不会有什么问题。

如果没有看到这样的信息, 或者您不确定, 则从头开始构建将是万无一失的做法。

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

  • 以单用户模式运行

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

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

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

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

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

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

    # mount -u -o noatime /usr/src
    

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

  • 存放 /usr/obj 的文件系统可以使用 async 选项被挂接 (或重新挂接)。 这样做将启用异步写盘。 换句话说, 对应用程序而言写会立即完成, 而数据则延迟几秒才会写到盘里。 这样做能够成批地写下数据, 从而极大地改善性能。

    警告: 注意, 这个选项会使您的文件系统变得脆弱。 使用这个选项会提高在电源断掉或机器非正常重启时, 文件系统进入不可恢复状态的概率。

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

    # mount -u -o async /usr/obj
    

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

21.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 一般问题邮件列表 邮件列表。准备回答其它关于您的设置的问题!

本文档和其它文档可从这里下载:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题,请先阅读文档,如不能解决再联系<[email protected]>.
关于本文档的问题请发信联系 <[email protected]>.