23.4. 重新編譯 “world”

在更新 FreeBSD 的 source tree 到最新之後(無論是 FreeBSD-STABLE、 FreeBSD-CURRENT 等等),接下來就可以用這些 source tree 來重新編譯系統 。

做好備份在作任何大動作 之前 要記得先把系統作備份的重要性無須強調。 儘管重新編譯 world 是 (只要有照文件指示去作的話)一件很簡單的事情,但出錯也是在所難免的。 另外,別人在 source tree 不慎搞混的錯誤,也可能會造成系統無法開機 。

請確認自己已作妥相關備份,並且手邊有 fixit 磁片或開機光碟。 您可能永遠也用不到這些東西, 但安全第一總比事後說抱歉來得好吧!

訂閱相關的 Mailing ListFreeBSD-STABLE 以及 FreeBSD-CURRENT 分支,本質上就是屬於 開發階段。 為 FreeBSD 作貢獻的也都是人,偶爾也會犯錯誤。

有時候這些錯誤並無大礙,只是會讓系統產生新的錯誤警告而已。 有時則是災難,可能會導致不能開機或檔案系統的毀損(或更糟)。

若遇到類似問題,貼封標題為 “heads up(注意)” 開頭的信到相關的 mailing list,並講清楚問題點以及會影響哪些系統。 在問題獲解決後,再貼標題為 “all clear(已解決)” 開頭的聲明信。

若用的是 FreeBSD-STABLE 或 FreeBSD-CURRENT,卻又不閱讀 FreeBSD-STABLE 郵遞論壇FreeBSD-CURRENT 郵遞論壇 的討論,那麼會是自找麻煩而已。

不要用 make world一堆早期的舊文件都會建議說使用 make world。 這樣做會跳過一些重要步驟,建議只有在你知道自己在作什麼,再這麼做。 在絕大多數的情況下,請不要亂用 make world, 而該改用下面介紹的方式。

23.4.1. 更新系統的標準方式

要升級系統前,一定要先查閱 /usr/src/UPDATING 文件,以瞭解 buildworld 之前需要作哪些事情或注意事項, 然後才用下列步驟:

# make buildworld
# make buildkernel
# make installkernel
# reboot

注: 在少數狀況,可能需要先在 buildworld 步驟之前先作 mergemaster -p 才能完成。 至於何時需要或不需要,請參閱 UPDATING 內的說明。 一般來說,只要不是進行跨版號(major)的 FreeBSD 版本升級, 就可略過這步驟。

完成 installkernel 之後,需要重開機並切到 single user 模式(舉例:也可以在 loader 提示符號後面加上 boot -s)。 接下來執行:

# mergemaster -p
# make installworld
# mergemaster
# reboot

Read Further Explanations上述步驟只是協助您升級的簡單說明而已,若要清楚瞭解每一步驟, 尤其是若欲自行打造 kernel 設定,就更該閱讀下面的內容。

23.4.2. 閱讀 /usr/src/UPDATING

在作任何事情之前,請務必先閱讀 /usr/src/UPDATING (或在 source code 內類似的文件) 。 這份文件會寫到可能遭遇的問題,或指定那些會執行的指令順序為何。 如果你機器現在的 UPDATING 文件與這邊的描述有衝突、矛盾之處,那麼請以機器上的 UPDATING 為準。

重要: 然而,如同先前所述,單單只靠閱讀 UPDATING 並不能完全取代 mailing list。 這兩者都是互補的,而不相排斥。

23.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 複製 CFLAGS 以及 NO_PROFILE 之類的設定到 /etc/make.conf,並解除相關註解印記 。

此外,也可以試試看其他設定 (COPTFLAGSNOPORTDOCS 等等),是否符合自己所需。

23.4.4. 更新 /etc 內的設定檔

/etc 目錄會有系統的相關設定檔, 以及開機時的各項服務啟動 script。 有些 script 隨 FreeBSD 版本的不同而有些差異。

其中有些設定檔會在每日運作的系統裡也會用到。 尤其是 /etc/group

有時候在 make installworld 安裝過程中, 會需要先建立某些特定帳號或群組。 在進行升級之前,它們可能並不存在, 因此升級時就會造成問題。 有時候 make buildworld 會先檢查這些所需的帳號或群組是否已有存在。

舉個這樣的例子,像是某次升級之後必須新增 smmsp 帳號。 若使用者尚未新增該帳號就要完成升級操作的話, 會在 mtree(8) 嘗試建立 /var/spool/clientmqueue 時發生失敗。

解法是在 buildworld 階段之前,先執行 mergemaster(8) 並搭配 -p 選項。 它會比對那些執行 buildworldinstallworld 所需之關鍵設定檔。 若你所用的是早期仍未支援 -pmergemaster 版本,那麼直接使用 source tree 內的新版即可:

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

提示: 若您是偏執狂(paranoid), 可以像下面這樣去試著檢查系統上有哪些檔案屬於已改名或被刪除的群組 :

# find / -group GID -print

這會顯示所有符合要找的 GID 群組 (可以是群組名稱,或者是群組的數字代號)的所有檔案。

23.4.5. 切換到 Single User 模式

您可能會想在 single user 模式下編譯系統。 除了可以明顯更快完成之外,安裝過程中將會牽涉許多重要的系統檔案, 包括所有系統 binaries、libraries、include 檔案等。 若在運作中的系統(尤其有許多使用者在用的時候)內更改這些檔案, 那簡直是自找麻煩的作法。

另一種模式是先在 multi-user 模式下編譯好系統,然後再切到 single user 模式去安裝。 若您比較喜歡這種方式,只需在 build(編譯過程) 完成之後, 再去執行下面的步驟即可。 一直到可切換 single user 模式時,再去執行 installkernelinstallworld 即可。

切換為 root 身份打:

# shutdown now

這樣就會從原本的 multi-user 模式切換到 single user 模式。

除此之外也可以重開機,接著在開機選單處選擇 “single user” 選項。 如此一來就會進入 single user 模式, 然後在 shell 提示符號處輸入:

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

這樣會先檢查檔案系統,並重新將 / 改以可讀寫的模式掛載,以及 /etc/fstab 內所設定的其他 UFS 檔案系統,最後啟用 swap 磁區。

注: 若 CMOS 時鐘是設為當地時間,而非 GMT 時區(若 date(1) 指令沒顯示正確的時間、時區),那可能需要再輸入下列指令:

# adjkerntz -i

這步驟可以確認您的當地時區設定是否正確 —— 否則日後會造成一些問題。

23.4.6. 移除 /usr/obj

在重新編譯系統的過程中,編譯結果會放到(預設情況) /usr/obj 內。 這裡面的目錄會對應到 /usr/src 的目錄結構。

砍掉這目錄,可以讓以後的 make buildworld 過程更快一些,而且可避免以前編譯的東西跟現在的混淆在一起的相依錯亂 。

而有些 /usr/obj 內的檔案可能會設定不可更動的 flag(細節請參閱 chflags(1)),而必須先拿掉這些 flag 設定才行 。

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

23.4.7. 重新編譯 Base System

23.4.7.1. 保留編譯的紀錄

建議養成好習慣,把執行 make(1) 時產生的紀錄存起來。 這樣若有哪邊出錯,就會有錯誤訊息的紀錄。 雖然單單這樣, 你可能不知道如何分析是哪邊出了岔,但若把你問題記錄貼到 FreeBSD 相關的 mailing list 就可以有人可以幫忙看是怎麼一回事情。

最簡單的方是就是用 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 的家目錄。

23.4.7.2. 編譯 Base System

首先請先切換到 /usr/src 目錄:

# cd /usr/src

(當然,除非你把 source code 放到其他地方,若真是這樣, 就切換到那個目錄即可)。

使用 make(1) 指令來重新編譯 world。 這指令會從 Makefile 檔(這檔會寫 FreeBSD 的程式該如何重新編譯、以哪些順序來編譯等等)去讀取相關指令。

一般下指令的格式如下:

# make -x -DVARIABLE target

在這個例子,-x 是你想傳給 make(1) 的選項,細節說明請參閱 make(1) 說明, 裡面有相關範例說明。

-DVARIABLE 則是把變數設定傳給 Makefile。 這些變數會控制 Makefile 的行為。 這些設定與 /etc/make.conf 的變數設定是一樣, 只是另一種設定方式而已。

# make -DNO_PROFILE target

上面的例子則是另一種設定方式,也就是哪些不要。 這個例子中的意思是不去編譯 profiled libraries,效果就如同設定在 /etc/make.conf

NO_PROFILE=    true 	#    Avoid compiling profiled libraries

target 則是告訴 make(1) 該去做哪些。 每個 Makefile 都會定義不同的 “targets”,然後依您所給的 target 就會決定會做哪些動作 。

Some targets are listed in the Makefile, but are not meant for you to run. Instead, they are used by the build process to break out the steps necessary to rebuild the system into a number of sub-steps.

Most of the time you will not need to pass any parameters to make(1), and so your command like will look like this:

# make target

Where target will be one of many build options. The first target should always be buildworld.

As the names imply, buildworld builds a complete new tree under /usr/obj, and installworld, another target, installs this tree on the current machine.

Having separate options is very useful for two reasons. First, it allows you to do the build safe in the knowledge that no components of your running system will be affected. The build is “self hosted”. Because of this, you can safely run buildworld on a machine running in multi-user mode with no fear of ill-effects. It is still recommended that you run the installworld part in single user mode, though.

Secondly, it allows you to use NFS mounts to upgrade multiple machines on your network. If you have three machines, A, B and C that you want to upgrade, run make buildworld and make installworld on A. B and C should then NFS mount /usr/src and /usr/obj from A, and you can then run make installworld to install the results of the build on B and C.

Although the world target still exists, you are strongly encouraged not to use it.

Run

# make buildworld

It is possible to specify a -j option to make which will cause it to spawn several simultaneous processes. This is most useful on multi-CPU machines. However, since much of the compiling process is IO bound rather than CPU bound it is also useful on single CPU machines.

On a typical single-CPU machine you would run:

# make -j4 buildworld

make(1) will then have up to 4 processes running at any one time. Empirical evidence posted to the mailing lists shows this generally gives the best performance benefit.

If you have a multi-CPU machine and you are using an SMP configured kernel try values between 6 and 10 and see how they speed things up.

23.4.7.3. Timings

Many factors influence the build time, but fairly recent machines may only take a one or two hours to build the FreeBSD-STABLE tree, with no tricks or shortcuts used during the process. A FreeBSD-CURRENT tree will take somewhat longer.

23.4.8. Compile and Install a New Kernel

To take full advantage of your new system you should recompile the kernel. This is practically a necessity, as certain memory structures may have changed, and programs like ps(1) and top(1) will fail to work until the kernel and source code versions are the same.

The simplest, safest way to do this is to build and install a kernel based on GENERIC. While GENERIC may not have all the necessary devices for your system, it should contain everything necessary to boot your system back to single user mode. This is a good test that the new system works properly. After booting from GENERIC and verifying that your system works you can then build a new kernel based on your normal kernel configuration file.

On FreeBSD it is important to build world before building a new kernel.

注: If you want to build a custom kernel, and already have a configuration file, just use KERNCONF=MYKERNEL like this:

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

Note that if you have raised kern.securelevel above 1 and you have set either the noschg or similar flags to your kernel binary, you might find it necessary to drop into single user mode to use installkernel. Otherwise you should be able to run both these commands from multi user mode without problems. See init(8) for details about kern.securelevel and chflags(1) for details about the various file flags.

23.4.9. Reboot into Single User Mode

You should reboot into single user mode to test the new kernel works. Do this by following the instructions in µÚ 23.4.5 節.

23.4.10. Install the New System Binaries

If you were building a version of FreeBSD recent enough to have used make buildworld then you should now use installworld to install the new system binaries.

Run

# cd /usr/src
# make installworld

注: If you specified variables on the make buildworld command line, you must specify the same variables in the make installworld command line. This does not necessarily hold true for other options; for example, -j must never be used with installworld.

For example, if you ran:

# make -DNO_PROFILE buildworld

you must install the results with:

# make -DNO_PROFILE installworld

otherwise it would try to install profiled libraries that had not been built during the make buildworld phase.

23.4.11. Update Files Not Updated by make installworld

Remaking the world will not update certain directories (in particular, /etc, /var and /usr) with new or changed configuration files.

The simplest way to update these files is to use mergemaster(8), though it is possible to do it manually if you would prefer to do that. Regardless of which way you choose, be sure to make a backup of /etc in case anything goes wrong.

23.4.11.1. mergemaster

Contributed by Tom Rhodes.

The mergemaster(8) utility is a Bourne script that will aid you in determining the differences between your configuration files in /etc, and the configuration files in the source tree /usr/src/etc. This is the recommended solution for keeping the system configuration files up to date with those located in the source tree.

To begin simply type mergemaster at your prompt, and watch it start going. mergemaster will then build a temporary root environment, from / down, and populate it with various system configuration files. Those files are then compared to the ones currently installed in your system. At this point, files that differ will be shown in diff(1) format, with the + sign representing added or modified lines, and - representing lines that will be either removed completely, or replaced with a new line. See the diff(1) manual page for more information about the diff(1) syntax and how file differences are shown.

mergemaster(8) will then show you each file that displays variances, and at this point you will have the option of either deleting the new file (referred to as the temporary file), installing the temporary file in its unmodified state, merging the temporary file with the currently installed file, or viewing the diff(1) results again.

Choosing to delete the temporary file will tell mergemaster(8) that we wish to keep our current file unchanged, and to delete the new version. This option is not recommended, unless you see no reason to change the current file. You can get help at any time by typing ? at the mergemaster(8) prompt. If the user chooses to skip a file, it will be presented again after all other files have been dealt with.

Choosing to install the unmodified temporary file will replace the current file with the new one. For most unmodified files, this is the best option.

Choosing to merge the file will present you with a text editor, and the contents of both files. You can now merge them by reviewing both files side by side on the screen, and choosing parts from both to create a finished product. When the files are compared side by side, the l key will select the left contents and the r key will select contents from your right. The final output will be a file consisting of both parts, which can then be installed. This option is customarily used for files where settings have been modified by the user.

Choosing to view the diff(1) results again will show you the file differences just like mergemaster(8) did before prompting you for an option.

After mergemaster(8) is done with the system files you will be prompted for other options. mergemaster(8) may ask if you want to rebuild the password file and will finish up with an option to remove left-over temporary files.

23.4.11.2. Manual Update

If you wish to do the update manually, however, you cannot just copy over the files from /usr/src/etc to /etc and have it work. Some of these files must be “installed” first. This is because the /usr/src/etc directory is not a copy of what your /etc directory should look like. In addition, there are files that should be in /etc that are not in /usr/src/etc.

If you are using mergemaster(8) (as recommended), you can skip forward to the next section.

The simplest way to do this by hand is to install the files into a new directory, and then work through them looking for differences.

Backup Your Existing /etcAlthough, in theory, nothing is going to touch this directory automatically, it is always better to be sure. So copy your existing /etc directory somewhere safe. Something like:

# cp -Rp /etc /etc.old

-R does a recursive copy, -p preserves times, ownerships on files and suchlike.

You need to build a dummy set of directories to install the new /etc and other files into. /var/tmp/root is a reasonable choice, and there are a number of subdirectories required under this as well.

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

This will build the necessary directory structure and install the files. A lot of the subdirectories that have been created under /var/tmp/root are empty and should be deleted. The simplest way to do this is to:

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

This will remove all empty directories. (Standard error is redirected to /dev/null to prevent the warnings about the directories that are not empty.)

/var/tmp/root now contains all the files that should be placed in appropriate locations below /. You now have to go through each of these files, determining how they differ with your existing files.

Note that some of the files that will have been installed in /var/tmp/root have a leading “.”. At the time of writing the only files like this are shell startup files in /var/tmp/root/ and /var/tmp/root/root/, although there may be others (depending on when you are reading this). Make sure you use ls -a to catch them.

The simplest way to do this is to use diff(1) to compare the two files:

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

This will show you the differences between your /etc/shells file and the new /var/tmp/root/etc/shells file. Use these to decide whether to merge in changes that you have made or whether to copy over your old file.

Name the New Root Directory (/var/tmp/root) with a Time Stamp, so You Can Easily Compare Differences Between Versions: Frequently rebuilding the world means that you have to update /etc frequently as well, which can be a bit of a chore.

You can speed this process up by keeping a copy of the last set of changed files that you merged into /etc. The following procedure gives one idea of how to do this.

  1. Make the world as normal. When you want to update /etc and the other directories, give the target directory a name based on the current date. If you were doing this on the 14th of February 1998 you could do the following:

    # mkdir /var/tmp/root-19980214
    # cd /usr/src/etc
    # make DESTDIR=/var/tmp/root-19980214 \
        distrib-dirs distribution
    
  2. Merge in the changes from this directory as outlined above.

    Do not remove the /var/tmp/root-19980214 directory when you have finished.

  3. When you have downloaded the latest version of the source and remade it, follow step 1. This will give you a new directory, which might be called /var/tmp/root-19980221 (if you wait a week between doing updates).

  4. You can now see the differences that have been made in the intervening week using diff(1) to create a recursive diff between the two directories:

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

    Typically, this will be a much smaller set of differences than those between /var/tmp/root-19980221/etc and /etc. Because the set of differences is smaller, it is easier to migrate those changes across into your /etc directory.

  5. You can now remove the older of the two /var/tmp/root-* directories:

    # rm -rf /var/tmp/root-19980214
    
  6. Repeat this process every time you need to merge in changes to /etc.

You can use date(1) to automate the generation of the directory names:

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

23.4.12. Rebooting

You are now done. After you have verified that everything appears to be in the right place you can reboot the system. A simple shutdown(8) should do it:

# shutdown -r now

23.4.13. Finished

You should now have successfully upgraded your FreeBSD system. Congratulations.

If things went slightly wrong, it is easy to rebuild a particular piece of the system. For example, if you accidentally deleted /etc/magic as part of the upgrade or merge of /etc, the file(1) command will stop working. In this case, the fix would be to run:

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

23.4.14. Questions

23.4.14.1. Do I need to re-make the world for every change?
23.4.14.2.
23.4.14.3. Can I remove /usr/obj when I have finished?
23.4.14.4. Can interrupted builds be resumed?
23.4.14.5. How can I speed up making the world?
23.4.14.6. What do I do if something goes wrong?

23.4.14.1. Do I need to re-make the world for every change?

There is no easy answer to this one, as it depends on the nature of the change. For example, if you just ran CVSup, and it has shown the following files as being updated:

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

it probably is not worth rebuilding the entire world. You could just go to the appropriate sub-directories and make all install, and that's about it. But if something major changed, for example src/lib/libc/stdlib then you should either re-make the world, or at least those parts of it that are statically linked (as well as anything else you might have added that is statically linked).

At the end of the day, it is your call. You might be happy re-making the world every fortnight say, and let changes accumulate over that fortnight. Or you might want to re-make just those things that have changed, and be confident you can spot all the dependencies.

And, of course, this all depends on how often you want to upgrade, and whether you are tracking FreeBSD-STABLE or FreeBSD-CURRENT.

23.4.14.2.

My compile failed with lots of signal 11 (or other signal number) errors. What has happened?

This is normally indicative of hardware problems. (Re)making the world is an effective way to stress test your hardware, and will frequently throw up memory problems. These normally manifest themselves as the compiler mysteriously dying on receipt of strange signals.

A sure indicator of this is if you can restart the make and it dies at a different point in the process.

In this instance there is little you can do except start swapping around the components in your machine to determine which one is failing.

23.4.14.3. Can I remove /usr/obj when I have finished?

The short answer is yes.

/usr/obj contains all the object files that were produced during the compilation phase. Normally, one of the first steps in the make buildworld process is to remove this directory and start afresh. In this case, keeping /usr/obj around after you have finished makes little sense, and will free up a large chunk of disk space (currently about 340 MB).

However, if you know what you are doing you can have make buildworld skip this step. This will make subsequent builds run much faster, since most of sources will not need to be recompiled. The flip side of this is that subtle dependency problems can creep in, causing your build to fail in odd ways. This frequently generates noise on the FreeBSD mailing lists, when one person complains that their build has failed, not realizing that it is because they have tried to cut corners.

23.4.14.4. Can interrupted builds be resumed?

This depends on how far through the process you got before you found a problem.

In general (and this is not a hard and fast rule) the make buildworld process builds new copies of essential tools (such as gcc(1), and make(1)) and the system libraries. These tools and libraries are then installed. The new tools and libraries are then used to rebuild themselves, and are installed again. The entire system (now including regular user programs, such as ls(1) or grep(1)) is then rebuilt with the new system files.

If you are at the last stage, and you know it (because you have looked through the output that you were storing) then you can (fairly safely) do:

… fix the problem …
# cd /usr/src
# make -DNO_CLEAN all

This will not undo the work of the previous make buildworld.

If you see the message:

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

in the make buildworld output then it is probably fairly safe to do so.

If you do not see that message, or you are not sure, then it is always better to be safe than sorry, and restart the build from scratch.

23.4.14.5. How can I speed up making the world?

  • Run in single user mode.

  • Put the /usr/src and /usr/obj directories on separate file systems held on separate disks. If possible, put these disks on separate disk controllers.

  • Better still, put these file systems across multiple disks using the ccd(4) (concatenated disk driver) device.

  • Turn off profiling (set “NO_PROFILE=true” in /etc/make.conf). You almost certainly do not need it.

  • Also in /etc/make.conf, set CFLAGS to something like -O -pipe. The optimization -O2 is much slower, and the optimization difference between -O and -O2 is normally negligible. -pipe lets the compiler use pipes rather than temporary files for communication, which saves disk access (at the expense of memory).

  • Pass the -jn option to make(1) to run multiple processes in parallel. This usually helps regardless of whether you have a single or a multi processor machine.

  • The file system holding /usr/src can be mounted (or remounted) with the noatime option. This prevents the file system from recording the file access time. You probably do not need this information anyway.

    # mount -u -o noatime /usr/src
    

    警告The example assumes /usr/src is on its own file system. If it is not (if it is a part of /usr for example) then you will need to use that file system mount point, and not /usr/src.

  • The file system holding /usr/obj can be mounted (or remounted) with the async option. This causes disk writes to happen asynchronously. In other words, the write completes immediately, and the data is written to the disk a few seconds later. This allows writes to be clustered together, and can be a dramatic performance boost.

    警告Keep in mind that this option makes your file system more fragile. With this option there is an increased chance that, should power fail, the file system will be in an unrecoverable state when the machine restarts.

    If /usr/obj is the only thing on this file system then it is not a problem. If you have other, valuable data on the same file system then ensure your backups are fresh before you enable this option.

    # mount -u -o async /usr/obj
    

    警告As above, if /usr/obj is not on its own file system, replace it in the example with the name of the appropriate mount point.

23.4.14.6. What do I do if something goes wrong?

Make absolutely sure your environment has no extraneous cruft from earlier builds. This is simple enough.

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

Yes, make cleandir really should be run twice.

Then restart the whole process, starting with make buildworld.

If you still have problems, send the error and the output of uname -a to FreeBSD general questions 郵遞論壇. Be prepared to answer other questions about your setup!

本文及其他文件,可由此下載:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/

若有 FreeBSD 方面疑問,請先閱讀 FreeBSD 相關文件,如不能解決的話,再洽詢 <questions@FreeBSD.org>。
關於本文件的問題,請洽詢 <doc@FreeBSD.org>。