在更新 FreeBSD 的 source tree 到最新之後(無論是 FreeBSD-STABLE、 FreeBSD-CURRENT 等等),接下來就可以用這些 source tree 來重新編譯系統 。
在作任何大動作 之前 要記得先把系統作備份的重要性無須強調。 儘管重新編譯 world 是 (只要有照文件指示去作的話)一件很簡單的事情,但出錯也是在所難免的。 另外,別人在 source tree 不慎搞混的錯誤,也可能會造成系統無法開機 。
請確認自己已作妥相關備份,並且手邊有 fixit 磁片或開機光碟。 您可能永遠也用不到這些東西, 但安全第一總比事後說抱歉來得好吧!
FreeBSD-STABLE 以及 FreeBSD-CURRENT 分支,本質上就是屬於 開發階段。 為 FreeBSD 作貢獻的也都是人,偶爾也會犯錯誤。
有時候這些錯誤並無大礙,只是會讓系統產生新的錯誤警告而已。 有時則是災難,可能會導致不能開機或檔案系統的毀損(或更糟)。
若遇到類似問題,貼封標題為 “heads up(注意)” 開頭的信到相關的 mailing list,並講清楚問題點以及會影響哪些系統。 在問題獲解決後,再貼標題為 “all clear(已解決)” 開頭的聲明信。
若用的是 FreeBSD-STABLE 或 FreeBSD-CURRENT,卻又不閱讀 FreeBSD-STABLE 郵遞論壇 或 FreeBSD-CURRENT 郵遞論壇 的討論,那麼會是自找麻煩而已。
make world
: 一堆早期的舊文件都會建議說使用 make world
。
這樣做會跳過一些重要步驟,建議只有在你知道自己在作什麼,再這麼做。
在絕大多數的情況下,請不要亂用 make world
,
而該改用下面介紹的方式。
要升級系統前,一定要先查閱 /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
上述步驟只是協助您升級的簡單說明而已,若要清楚瞭解每一步驟, 尤其是若欲自行打造 kernel 設定,就更該閱讀下面的內容。
在作任何事情之前,請務必先閱讀
/usr/src/UPDATING
(或在 source code 內類似的文件)
。 這份文件會寫到可能遭遇的問題,或指定那些會執行的指令順序為何。
如果你機器現在的 UPDATING
文件與這邊的描述有衝突、矛盾之處,那麼請以機器上的
UPDATING
為準。
然而,如同先前所述,單單只靠閱讀 UPDATING
並不能完全取代 mailing list。 這兩者都是互補的,而不相排斥。
檢查
/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
目錄會有系統的相關設定檔,
以及開機時的各項服務啟動 script。 有些 script 隨 FreeBSD
版本的不同而有些差異。
其中有些設定檔會在每日運作的系統裡也會用到。 尤其是
/etc/group
。
有時候在 make installworld
安裝過程中,
會需要先建立某些特定帳號或群組。 在進行升級之前,它們可能並不存在,
因此升級時就會造成問題。 有時候 make buildworld
會先檢查這些所需的帳號或群組是否已有存在。
舉個這樣的例子,像是某次升級之後必須新增 smmsp
帳號。 若使用者尚未新增該帳號就要完成升級操作的話,
會在 mtree(8) 嘗試建立 /var/spool/clientmqueue
時發生失敗。
解法是在 buildworld 階段之前,先執行 mergemaster(8) 並搭配
-p
選項。 它會比對那些執行
buildworld
或
installworld
所需之關鍵設定檔。
若你所用的是早期仍未支援 -p
的
mergemaster
版本,那麼直接使用 source tree
內的新版即可:
#
cd /usr/src/usr.sbin/mergemaster
#
./mergemaster.sh -p
若您是偏執狂(paranoid), 可以像下面這樣去試著檢查系統上有哪些檔案屬於已改名或被刪除的群組 :
#
find / -group GID -print
這會顯示所有符合要找的 GID
群組
(可以是群組名稱,或者是群組的數字代號)的所有檔案。
您可能會想在 single user 模式下編譯系統。 除了可以明顯更快完成之外,安裝過程中將會牽涉許多重要的系統檔案, 包括所有系統 binaries、libraries、include 檔案等。 若在運作中的系統(尤其有許多使用者在用的時候)內更改這些檔案, 那簡直是自找麻煩的作法。
另一種模式是先在 multi-user 模式下編譯好系統,然後再切到 single user
模式去安裝。 若您比較喜歡這種方式,只需在 build(編譯過程) 完成之後,
再去執行下面的步驟即可。 一直到可切換 single user 模式時,再去執行
installkernel
或
installworld
即可。
切換為 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
這步驟可以確認您的當地時區設定是否正確 — 否則日後會造成一些問題。
在重新編譯系統的過程中,編譯結果會放到(預設情況)
/usr/obj
內。 這裡面的目錄會對應到
/usr/src
的目錄結構。
砍掉這目錄,可以讓以後的 make buildworld
過程更快一些,而且可避免以前編譯的東西跟現在的混淆在一起的相依錯亂
。
而有些 /usr/obj
內的檔案可能會設定不可更動的
flag(細節請參閱 chflags(1)),而必須先拿掉這些 flag 設定才行
。
#
cd /usr/obj
#
chflags -R noschg *
#
rm -rf *
建議養成好習慣,把執行 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
的家目錄。
首先請先切換到 /usr/src
目錄:
#
cd /usr/src
(當然,除非你把 source code 放到其他地方,若真是這樣, 就切換到那個目錄即可)。
使用 make(1) 指令來重新編譯 world。
這指令會從 Makefile
檔(這檔會寫 FreeBSD
的程式該如何重新編譯、以哪些順序來編譯等等)去讀取相關指令。
一般下指令的格式如下:
#
make -x -DVARIABLE target
在這個例子,-
是你想傳給 make(1) 的選項,細節說明請參閱 make(1) 說明,
裡面有相關範例說明。x
-D
則是把變數設定傳給 VARIABLE
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.
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.
You should reboot into single user mode to test the new kernel works. Do this by following the instructions in 節 23.4.5, “切換到 Single User 模式”.
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.
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.
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.
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.
/etc
: Although, 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.
/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.
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
Merge in the changes from this directory as outlined above.
Do not remove the
/var/tmp/root-19980214
directory when you
have finished.
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).
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.
You can now remove the older of the two
/var/tmp/root-*
directories:
#
rm -rf /var/tmp/root-19980214
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"`
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
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.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:
it probably is not worth rebuilding the entire world.
You could just go to the appropriate sub-directories and
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 |
The short answer is yes.
However, if you know what you are doing you can have
| |
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 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 … This will not undo the work of the previous
If you see the message: -------------------------------------------------------------- Building everything.. -------------------------------------------------------------- in the 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? |
| |
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.
Yes, Then restart the whole process, starting
with If you still have problems, send the error and the
output of |
本文及其他文件,可由此下載: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/。
若有 FreeBSD 方面疑問,請先閱讀
FreeBSD 相關文件,如不能解決的話,再洽詢
<questions@FreeBSD.org>。
關於本文件的問題,請洽詢
<doc@FreeBSD.org>。