只要您根据一定版本的 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
都是不应该做的事情, 您应该使用这里描述的方法。
在更新系统时, 一定要首先查看
/usr/src/UPDATING
文件, 以便了解在 buildworld
之前需要进行的操作, 然后按照下面列出的步骤进行操作:
这些更新步骤假定您使用的是包含旧编译器、 内核以及用户态工具及配置的旧版 FreeBSD。 我们使用 “world” 来表示系统中的核心执行文件、 函数库和程序文件。 编译器是 “world” 的一部分, 但有其特殊性。
此外, 我们还假定您已经获得了较新版本操作系统的源代码。 如果您正更新的系统中的源代码也是旧版系统所附带的, 您还需要参阅 第 25.6 节 “同步您的源码” 来把代码同步到较新的版本。
从源代码更新系统, 有时会比初看上去的时候更麻烦一些, 另一方面, FreeBSD 的开发人员有时会不得不修改推荐的更新步骤, 特别是当出现了一些无法避免的依赖关系的时候。 这一节余下的部分, 将介绍目前推荐的更新步骤背后的原理。
成功的更新操作必须解决下面的这些问题:
旧的编译器可能无法编译新的内核。 (另一方面, 旧的编译器很可能有 bug。) 因此, 新的内核应该以新的编译器编译。 更具体地说, 新的编译器应在新内核开始联编之前已经完成了联编步骤。 请注意, 新的编译器并不一定需要在联编新内核之前 安装 到系统中。
新的 world 有可能依赖一些新的内核特性。 因此, 新内核必须在新的 world 之前安装。
这两个问题就是为什么我们将在后面的章节中介绍的,
需要按照 buildworld
、
buildkernel
、
installkernel
、
installworld
的顺序来更新系统的原因。
这并不是您需要遵守推荐的更新操作的全部原因,
除了这两个最重要的理由之外, 还有一些并不那么显而易见的原因:
旧的 world 可能无法配合新的内核正常工作, 因此, 您在安装完新内核之后, 应尽快将 world 也随之更新。
有些配置文件的变动必须在安装新的 world 之前完成, 而另一些配置文件的变动则有可能导致旧 world 工作不正常。 因此, 通常而言会需要两次不同的配置文件更新步骤。
多数情况下, 更新步骤只会替换或增加文件; 换言之, 现有的旧文件并不会被删除。 有时, 这可能会导致一些其他问题。 因此, 有时安装操作会指明, 必须在某些操作之前手工删除一些文件。 这些在未来可能会被自动化, 也可能不会自动化。
由于有这些考虑, 因此一般情况下我们建议使用下列更新步骤。 请注意, 具体的更新操作中可能会需要一些附加的步骤, 但核心的过程应该是不会轻易发生变化的:
make buildworld
这步操作会联编新的编译器, 以及少量相关工具,
并在随后使用新的编译器来联编
world。 联编的结果会存放在 /usr/obj
。
make buildkernel
与旧式的、 使用 config(8) 和
make(1) 的方法不同,
这种做法会使用存放于 /usr/obj
中的 新的 编译器。
这种做法使得您免去了由于编译器与内核源代码不一致导致的问题。
make installkernel
安装新的内核及其模块, 使系统能够以更新后的内核启动。
重启系统并进入单用户模式。
单用户模式使得更新正在运行的软件可能导致的问题减到最少。 此外, 它也使配合新内核运行旧 world 可能出现的问题减到最少。
mergemaster -p
这步操作会进行完成安装新的 world 所需的配置文件更新操作。
例如, 它可能会在系统的密码数据库中添加新的用户组或用户。
这些操作通常在上次更新之后增加了新的用户组或特殊系统用户之后是需要的,
因为 installworld
这步操作会需要这些用户或组才能顺利完成。
make installworld
从 /usr/obj
中复制 world。
这步操作之后, 您在盘上的系统, 包括内核和 world 就都是新的了。
mergemaster
更新余下的配置文件, 因为您的 world 已经更新完成了。
重启系统。
这步操作将加在新的内核, 以及新的 world 和更新过的配置文件。
注意, 如果您正从同一 FreeBSD 版本分支升级, 例如, 从 7.0 到
7.1, 则上述过程可能没有那么必要, 因为您不太可能遇到严重的编译器、
内核源代码、 用户态程序源代码或配置文件不匹配的情形。
旧式的 make world
然后再联编新内核的升级方法, 很可能有机会能够正常运作而完成升级工作。
但是, 在大版本升级的过程中, 不按照前面所介绍的操作来进行升级时, 便很可能遇到一些问题。
此外, 还需要注意的是, 有些时候升级的过程中
(例如从 4.X
到 5.0) 可能会需要一些额外的步骤
(例如在 installworld 之前更名或删除一些文件)。 请仔细阅读
/usr/src/UPDATING
这个文件,
特别是它的结尾部分所介绍的推荐的升级操作顺序。
由于开发人员发现不可能完全避免一些不匹配方面的问题, 这个过程一直在演化过程中。 不过幸运的是, 目前推荐的这个升级步骤, 应该能够在很长一段时间内不需要做任何调整。
总结一下, 目前推荐的从源代码升级 FreeBSD 的方法是:
有时, 可能需要额外地执行一次
mergemaster -p
才能够完成
buildworld
步骤。
这些要求, 会在 UPDATING
中进行描述。
一般而言, 您可以简单地跳过这一步, 只要进行的不是大跨度的
FreeBSD 版本升级。
在 installkernel
成功完成之后,
您需要引导到单用户模式 (举例而言,
可以在加载器提示后输入 boot -s
)。
接下来执行:
前面所给出的, 只是帮助您开始工作的简要说明。 要清楚地理解每一步, 特别是如果打算自行定制内核配置, 就应阅读下面的内容。
在您做其它事之前,请阅读
/usr/src/UPDATING
(或在您的源码里的等效的文件)。
这个文件要包含有关于您可能遇到的问题的重要信息,
或指定了您可能使用到的命令的执行顺序。如果
UPDATING
与您这里读到相矛盾,那就先依据
UPDATING
。
正如先前所述,阅读 UPDATING
并不能替代订阅正确的邮件列表。两都是互补的,并不彼此排斥。
检查
/usr/share/examples/etc/make.conf
以及
/etc/make.conf
。 第一个文件包含了一些默认的定义
– 它们中的绝大多数都注释掉了。
为了在重新编译系统时能够使用它们,
请把这些选项加入到 /etc/make.conf
。
请注意在 /etc/make.conf
中的任何设置同时也会影响每次运行
make
的结果, 因此设置一些适合自己系统的选项是一个好习惯。
一般的用户通常会从 /usr/share/examples/etc/make.conf
复制
CFLAGS
和
NO_PROFILE
这样的设置到
/etc/make.conf
中并令它们生效。
请考虑其他的一些选项 (例如 COPTFLAGS
、
NOPORTDOCS
等等), 看看是否合用。
/etc
目录包含有除了您的系统启动时执行的脚本外大部分的系统配置信息。
有些脚本随 FreeBSD 的版本而不同。
有些配置文件在天天运行的系统里也是要使用到的。尤其是
/etc/group
。
偶尔, 作为安装过程的一部分,
make installworld
会要求事先创建某些特定的用户或组。
在进行升级时, 它们可能并不存在。 这会给升级造成问题。
有时, make buildworld
会检查它们是否已经存在。
最近就有个这样的例子, 当时新增了 smmsp
用户。 当用户尝试完成安装操作时, 在 mtree(8) 尝试建立
/var/spool/clientmqueue
时失败了。
解决办法是通过使用 -p
选项以构建前 (pre-buildworld) 模式运行 mergemaster(8)。
这表示只对比那些对于成功执行 buildworld
或 installworld
起关键作用的文件。
在第一次这样做时, 如果使用的是早期的不支持
-p
的 mergemaster
版本的话,
使用源码中的新版本即可。
如果您是个偏执狂 (paranoid), 您可以检查您的系统看看哪个文件属于您已更名或删除了的那个组。
将显示所有 GID
组
(可以是组名也可以是数字地组 ID)所有的文件。
您可能想在单用户模式下编译系统。 除了对更快处理事情显然有好处外, 重装系统将触及许多重要的系统文件, 包括所有标准系统二进制文件、库文件、包含 (include) 文件等等。 在正运行的系统 (尤其是在有活跃的用户的时候) 中更改这些文件是自寻烦恼。
另一种模式是在多用户模式下编译系统,然后转换到单用户模式下安装。
如果您喜欢这种方式,只需在建立 (build) 完成后才执行下边的步骤。
您推迟转换到单用户模式下直到您必须 installkernel
或 installworld
。
从运行的系统里,以超级用户方式执行:
这样就会转换到单用户模式。
除此之外, 也可以重启系统, 并在启动菜单处选择 “single user”(单用户) 选项。 这样系统将以单用户模式启动。 接着, 在 shell 提示符处执行:
这会检查文件系统,重新将 /
以读/写模式挂接, 参考 /etc/fstab
挂接其它所有的 UFS 文件系统,然后启用交换区。
如果您的 CMOS 时钟是设置为本地时间,而不是 GMT (如果 date(1) 命令输出不能显示正确的时间和地区也确有其事), 您可能也需要执行下边的命令:
这样可以确定您正确的本地时区设置──不这样做, 您以后可能会碰到一些问题。
随着重新构建系统的进行, 编译结果会放到 (默认情况下)
/usr/obj
下。 这些目录会映射到
/usr/src
。
通过删除这个目录, 可以加速 make buildworld
的过程, 并避免相互依赖关系等复杂的问题。
/usr/obj
中的某些文件可能设置了不可改标记 (详情参见 chflags(1)),
需要首先去掉这些标志。
建议把执行 make(1) 后得到的输出存成一个文件。 如果什么地方出了错,您就会有个错误信息的备份。 尽管这样不能帮您分析哪里出了错, 但如果您把您的问题贴到某个邮件列表里就能帮助其他的人。
这样做最简单的办法是使用 script(1)
命令,同是带上参数指定存放输出的文件名。
您应在重建系统之前立即这样做,然后在过程完成时输入
exit
。
如果您这样做,就 不要 把文件存到
/tmp
里边。下次启动时,这个目录就会被清除掉。
存放的最好地方是 /var/tmp
(如上个实例)或
root
的主目录。
您必须在/usr/src
目录里边:
(当然,除非您的源码是在其它地方,真是这样的话更换成那个目录就行了)。
使用 make(1) 命令重建系统。这个命令会从
Makefile
(描述组成 FreeBSD 的程序应该怎样被重建,
以什么样的顺序建立等等) 里读取指令。
输入的一般命令格式如下:
这个例子里,-
是会传递给 make(1) 的一个选项。查看 make(1)
手册有您可用的选项例子。x
-D
传递一个变量给 VARIABLE
Makefile
。这些变量控制了
Makefile
的行为。这些同
/etc/make.conf
设置的变量一样,
只是提供了另一种设置它们的方法。
是另一种指定不被建立 (built) 的先定库
(profiled libraries) 的方式,协同
/etc/make.conf
里的
一起使用。
目标 (target)
告诉
make(1) 什么该做。每个 Makefile
定义了一定数量不同的“目标 (targets)”,
然后您选择的目标就决定了什么会发生。
有些目标列在 Makefile
里的,但并不意味着您要执行。相反,建立过程 (build process)
利用它们把重建系统的一些必要的步骤分割成几个子步骤。
大部分的时间不需要向 make(1) 传递参数,因此您的命令看起来可能象这样:
此处 target
表示的是若干编译选项。
多数情况下, 第一个 target 都应该是
buildworld
。
正如名字所暗示的,buildworld
在 /usr/obj
下边建立了一个全新的树, 然后使用另一个 target,
installworld
在当前的机器里安装它。
将这些选项分开有两个优点。 首先, 它允许您安全地完成建立
(build), 而不对正在运行的系统的组件产生影响。
构建过程是 “自主的 (self hosted)”。 因为这样,
您可以安全地在以多用户模式运行的机器里执行
buildworld
,而不用当心不良影响。
但是依然推荐您在单用户模式时运行
installworld
。
第二,允许您使用 NFS 挂接 (NFS mounts)
升级您网络里的多台计算机。如果您有三台
A
、B
和 C
想进行升级,在A
执行
make buildworld
和
make installworld
。 然后将
A
上的
/usr/src
和
/usr/obj
通过 NFS 挂接到
B
和 C
上, 接下来, 只需在
B
和 C
上使用
make installworld
来安装构建的结果就可以了。
尽管 world
target
仍然存在,强烈建议您不要用它。
运行
我们提供了一个试验性的功能, 可以在构建过程中为
make
指定 -j
参数,
令其在构建过程中同时启动多个并发的进程。 对于多 CPU 的机器而言,
这样做有助于发挥其性能。 不过, 由于编译过程中的瓶颈主要是在 IO
而不是 CPU 上, 因此它也会对单 CPU 的机器带来好处。
对典型的单 CPU 机器, 可以使用:
这样, make(1) 会最多同时启动 4 个进程。 从发到邮件列表中的经验看, 这样做能带来最佳的性能。
如果您使用的机器有多颗 CPU, 并且配置了 SMP 的内核, 也可以试试看 6 到 10 的数值, 并观察是否能带来构建性能上的改善。
要充分利用您的新系统,您应该重新编译内核。 这是很有必要的,因为特定的内存结构已经发生了改变,像 ps(1) 和 top(1) 这样的程序会不能工作, 除非内核同源码树的版本是一样的。
最简单、最安全的方式是 build 并安装一个基于
GENERIC
的内核。虽然
GENERIC
可能没有适合您的系统的所有必要的设备,
但它包括了启动您的系统到单用户模式所必需的内容。
这是个不错的检测新系统是否工作正常的测试。在从
GENERIC
启动、核实系统可以工作后,
您就可以建立 (build) 一个基于您的正常内核配置文件的新的内核了。
在 FreeBSD 中, 首先完成 build world 然后再编译新内核非常重要。
如果您想建立一个定制内核,而且已经有了配置文件,
只需象这样使用 KERNCONF=MYKERNEL:
注意,如果您已把 内核安全级别(kern.securelevel)
调高到了 1 以上,而且还设置了 noschg
或相似的标识到了您的内核二进制里边,您可能会发现转换到单用户模式里使用
installkernel
是很有必要的。
如果您没有设置它, 则应该也能毫无问题地在多用户模式执行这两个命令。 请参考
init(8) 以了解更多关于 内核安全级(kern.securelevel)
的信息;查看 chflags(1) 了解更多关于不同文件标识的信息。
您现在应使用
installworld
来安装新的系统二进制。
执行
如果在 make buildworld
的命令行指定了变量,您就必须在
make installworld
命令行里指定同样的变量。
对于其它的选项并不是必需的,如,-j
就不能同 installworld
一起使用。
举例,您执行了:
您就必须使用:
来安装结果,否则就要试着安装先定 (profiled) 的在
make buildworld
阶段没有建立 (built)
的二进制文件。
重新编译整个系统不会使用新的或改过的配置文件更新某些目录
(尤其像 /etc
、/var
和 /usr
)
更新这些文件最简单的方式就是使用
mergemaster(8),手工去做也是可以的,只要您愿意。
不管您选择哪一种,一定记得备份
/etc
以防出错。
mergemaster(8) 工具是个 Bourne 脚本,用于检测
/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) 可能会问您是否要重建密码文件, 并在最后提示您是否要删除余下的临时文件。
如果想要手工更新,但不要只是从
/usr/src/etc
把文件复制到
/etc
就了事。有些文件是必须先“安装”的。
这是因为 /usr/src/etc
目录并 不是
想像的那样是 /etc
目录的一个复制。事实上,有些是文件是
/etc
有的,而 /usr/src/etc
里边没有。
如果您使用 mergemaster(8) (作为推荐),您可以向前跳到 下一节。
手工做最简单的方式是安装这些文件到一个新的目录,完成后再来查找不同处。
/etc
: 虽然,理论上,没有什么会自动访问这个目录,
事情还是做稳操胜当一点。复制已有 /etc
到一个安全的地方,如:
-R
完成递归复制
(译者注:即可以复制目录以下的所有内容),-p
保留文件的时间、所属等等。
您需要建立一个虚目录 (a dummy set of directories)
来安装新的 /etc
和其它文件。
/var/tmp/root
是个不错的选择,
除此之外,还有一些子目录是需要的。
这样就建好了需要的目录结构,然后安装文件。在
/var/tmp/root
下建立的大部分子目录是空的,
而且要删除掉。最简单的方式是:
这样会删除所有的空目录。(标准的错误信息被重定向到了
/dev/null
,以防止关于非空目录的警告。)
/var/tmp/root
现在包含了应放在
/
下某个位置的所有文件。
您现在必须仔细检查每一个文件,检测它们与您已有的文件有多大不同。
注意,有些已经安装在 /var/tmp/root
下的文件有个“.”在开头。在写的时候,像这样唯一的文件是
/var/tmp/root/
和 /var/tmp/root/root/
里 shell 启动文件,尽管可能有其它的(依赖于您什么时候读取这个)。
确信使用 ls -a
可以看到它们。
最简单的方式是使用 diff(1) 去比较两个文件:
这会显示出 /etc/shells
文件和新的
/var/tmp/root/etc/shells
文件的不同处。
用这些来决定是合并您已做的变化还是复制您的旧文件过来。
/var/tmp/root
),这样您可以轻松地比较两个版本的不同: 频繁重建系统意味着必须频繁更新
/etc
,而这可能会有点烦琐。
在合并到 /etc
的文件里,
最新更改的您可以做个复制,由此加快这个(指更新)过程。
下边就给出了一个怎样做的主意。
像平常一样建立系统 (Make the world)。当您想更新
/etc
和其它目录里,
给目标目录一个含有当前日期的名字。假如您是 1998 年 2 月 14
日做的,您可以执行下边的:
如上边列出的,从这个目录合并变化。
在您完成后,不要 删除
/var/tmp/root-19980214
目录。
在您下载了最新版的源码并改过后,执行第一步。
这样将得到一个新的目录,可能叫做
/var/tmp/root-19980221
(如果等了一周做的升级)。
您现在能看到两个目录间的不同了---在隔周的时间里使用 diff(1) 建立递归 diff 产生的不同:
一般情况下,这两种间的不同处比
/var/tmp/root-19980221/etc
和
/etc
之间的不同要小很多。
因为不同点更小,也就更容易把这些变化移到您的
/etc
目录里边。
您现在可以删除早先的两个
/var/tmp/root-*
目录:
每次您需要合并这些变化到 /etc
里,就重复这个流程。
您可以使用 date(1) 自动产生目录的名称:
恭喜!您现在成功升级了您的 FreeBSD 系统。
如果还有轻微的错误,可以轻易地重建系统的选定部分。
例如,在部分升级或合并 /etc
时,您不小心删除了
/etc/magic
,file(1)
命令就会停止工作。这种情况下,执行下边进行修复:
25.7.14.1. | 每个变化您都须要重建系统吗? |
这个不好说,因为要看变化的情况。如,如果您刚运行了 CVSup,并得到下边更新的文件: src/games/cribbage/instr.csrc/games/sail/pl_main.csrc/release/sysinstall/config.csrc/release/sysinstall/media.csrc/share/mk/bsd.port.mk 这就不必重建整个系统。您只需到相关的子目录里执行
在这天后,就是您的事了。要是说每两个星期重建一下系统的话, 您可能会高兴。或者您可能只想重做改变过的部分, 确信您能找出所有依赖关系。 当然,所有这些依赖于您想升级的频率,和您是否想跟踪 FreeBSD-STABLE 或 FreeBSD-CURRENT。 | |
25.7.14.2. | |
这个通常表示硬件错误。 (重)建系统是个强压测试系统硬件的有效地方式, 并且常常产生内存错误。 这些正好表示它们自已做为编译器离奇地死于收到的奇怪信息。 一个确信的指示器是如果重新开始 make,并且整个过程中会死在不同的点上。 对于这种情况,您没有什么可做的,除了更换机器里的部件,看是哪一个坏了。 | |
25.7.14.3. | 我完成后可以删除 |
简短地说,可以。
不过, 如果您很了解整个过程, 也可以让
| |
25.7.14.4. | 中断的 build 可以被恢复吗? |
依赖于您在您找到问题之前整个过程进行了多远。 一般而言 (当然这并不是硬性规定),
如果您正处于最后一个阶段, 并且了解它 (因为您已经看过了所保存的输出) 则可以 (相当安全地) 做: … 问题修复 …# cd /usr/src# make -DNO_CLEAN all 这样就不会取消先前的
在“make buildworld”的输出中如果看到如下信息: --------------------------------------------------------------Building everything..-------------------------------------------------------------- 出现在 如果没有看到这样的信息, 或者您不确定, 则从头开始构建将是万无一失的做法。 | |
25.7.14.5. | 我怎样加快建立系统的速度? |
| |
25.7.14.6. | 如果出现了错误我该怎么办? |
绝对确信您的环境没有先前 build 留下的残余。这点够简单。 # chflags -R noschg /usr/obj/usr# rm -rf /usr/obj/usr# cd /usr/src# make cleandir# make cleandir 不错, 然后重新开始整个过程,使用 如果您还有问题,就把错误和 |
本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读
文档,如不能解决再联系
<questions@FreeBSD.org>.
关于本文档的问题请发信联系
<doc@FreeBSD.org>.