FreeBSD   make world

.逸晨


終於來到戲肉了 ^_^
請先確認您已擁有 FreeBSD 的系統原始碼 -- 請注意,是整個系統的原始碼,而非僅只有系統核心的原始碼。
在開始進行編譯系統的二進位碼時,請您務必先做個功課 -- 讀取 /usr/src/UPDATING 檔案,這個檔案內容描述整個版本的進度變化,以及您在待會將進行的工作中可能會遭遇到的困難排除方法,或者某個必需要先行設定、執行的工作。
假如 UPDATING 檔案中所提及的與您現在所查看的文件有所不同,請務必以 UPDATING 檔案內容為優先考量。

假若您對於 make world 的執行動作尚未熟悉(又是一句廢話,如果熟悉還來這幹嘛 ^_^),請先行照著如下的步驟來進行您的 make world。

檢查/設置 /etc/make.conf
檢查/更新 /etc/group
開始編譯系統 -- make world
更新 /etc/ 目錄
更新裝置節點 -- /dev
更新 /stand/ 目錄
編譯安裝新的核心

如果您從未設定過 /etc/make.conf 檔案的話,相信您一定無法在 /etc/ 目錄下找到 /etc/make.conf 這個檔案,您需要自行建立這個檔案。所幸的是 FreeBSD 一樣的也為您預先設置了個 make.conf 檔案,它的位置在 /etc/defaults/make.conf。
請將 /etc/defaults/make.conf 檔案覆製一份成為 /etc/make.conf。
因預設檔中是將所有的設置參數給先行註解起來的,也就是說『有等於沒有』,因此我們還得針對自己的需求來將所需的參數註解給移除,或甚至變更其參數值。
如果您先前已有設置過 /etc/make.conf 檔案了,也請您務必比對一下 /etc/defaults/make.conf 檔案中的內容,看看是否可用的參數有所變動,並依實情來重新配置您的 /etc/make.conf 內容,這個檢查動作在版本大跳躍時特別重要,請務必多加注意。

/etc/make.conf 這個檔案其實並非一定要存在的,沒有它的存在,您一樣能很快樂的使用您的 FreeBSD,但是如果您使用了它,相信您會更加快樂的。由 make.conf 這個檔案名稱中,我們不難聯想到與 make 這個編譯指令有關。是的,我們可以將一些固定使用的 make 參數給加進這個 make 參數設置檔裡頭,像是針對所使用的中央處理器 (CPU) 型號所設定的編譯參數 CPUTYPE=i686 或是指定使用 ports-tree 安裝套件時,抓取原始碼包的伺服器以加快原始碼包的下載速度︰

MASTER_SITE_BACKUP?= \
  ftp://ftp8.tw.freebsd.org/pub/FreeBSD/ports/distfiles/${DIST_SUBDIR}/\
  ftp://ftp3.tw.freebsd.org/pub/FreeBSD/ports/distfiles/${DIST_SUBDIR}/\
  ftp://ftp6.tw.freebsd.org/pub/FreeBSD/ports/distfiles/${DIST_SUBDIR}/\
  ftp://ftp7.tw.freebsd.org/pub/FreeBSD/ports/distfiles/${DIST_SUBDIR}/\
  ftp://ftp.tw.freebsd.org/pub/FreeBSD/ports/distfiles/${DIST_SUBDIR}/\
  ftp://ftp11.tw.freebsd.org/pub/FreeBSD/ports/distfiles/${DIST_SUBDIR}/
MASTER_SITE_OVERRIDE?=  ${MASTER_SITE_BACKUP}
一般來說,如果您只是個使用者而非程式開發員,您也許還會用得著 CFLAGSNOPROFILE 這兩個設定。請自行查看其他的參數選項說明,像是 COPTFLAGS、NOGAMES 之類的,自行打開你認為對你有用的吧。
在此有一點要提醒您的,凡是您於 /etc/make.conf 中所設置的參數,在您執行 make 指令時,如果該參數是可用的,一律會自動加上。
所以請您於執行 make 指令之前,請務必留意是否有哪個參數是必需先暫時先給予停止使用的。
最後,還是老話一句,請您 man make.conf(5) 來查知更多有關於 /etc/make.conf 的設置訊息。

在 make world 的過程中,會需要某些特定的 user 或 group 的存在,如果該特定的 user 或 group 不存在時,將會導致系統升級失敗。
請比較一下 /usr/src/etc/group 和你系統中的 group 檔有沒有一樣,如果有新增加的 group,那麼就把新的 group 名稱加到你的 /etc/group 裡面,記得要保持一樣的 GID 和 group 名稱。或許您會問,如果新的與舊的 group 有相衝到呢?那就放棄舊的 group 名稱吧,一切以 /usr/src/etc/group 中的為第一優先。
在先前的版本中,這個檢測工作是相當令人厭煩的,因為幾乎每次檢測的結果總是不用更新,因此常有人因而略過了這個步驟,直到真的發生錯誤時,才在一連串的偵測工作後想起 -- 我忘了更新 /etc/group 了。
幸運的是,自從 FreeBSD 4.6 RELEASE 發行之後,mergemaster(8) 指令多提供了個『-p』參數,執行 mergemaster -p 指令,它會去比對現行系統中要能成功的 make buildworld 或 make installworld 相關的檔案,並將訊息顯示於螢幕中,如果有比對出需更新的檔案內容,亦會停下等候您的決定 -- 當然,此時更新是唯一之道了。
如果您現行系統版本的 mergemaster 尚未提供『-p』這個參數,而您所抓取的系統原始碼是 4.6 RELEASE 之後的版本的話,那麼您可以使用如下的方式來更新︰
shell# cd /usr/src/usr.sbin/mergemaster
shell# .mergemaster.sh -p

在開始編譯前,您或許還有些事前工作要做︰
  • 備份您辛苦設定過 /etc/ 目錄下的設置檔案,特別是那些與網路服務與系統安全的部份。
  • 移除 /usr/obj/ 目錄。
    當系統重新編譯時,所有的檔案都將會被放置於 /usr/obj/ 目錄下,它是相對應於 /usr/src/ 目錄的。將此目錄先行刪除掉,可以免去清除先前編譯所遺留下的殘渣動作,以加快 make world 的速度,同時也可避免掉一些令人頭痛的相依性問題。
好了,現在可以開始進行編譯系統的工作了,不過這又可分成兩種模式來進行︰
  • 單機模式︰
    於單機模式下來編譯系統是個很好的決定,這將會使得編譯的速度快一些,同時當系統處於多重模式的狀態下,會有許多系統程式、函式庫、標頭檔等等正在使用中,而當系統編譯完成後進行安裝時,將會重新安裝 -- 亦即覆蓋這些系統檔案,而使用中的檔案將很可能會無法被覆蓋而造成安裝的失敗。在一個多重模式運作下的系統要來更新系統實在是自找麻煩的錯誤決定。
    您可以直接執行 shutdown now 指令來進入單機模式;或是重新啟動系統,於 boot 提示符號出現時,按下空白鍵以進入 boot shell,並卸載所有的模組 -- 如果您有事先載入的話,然後輸入 boot -s 來進入單機模式。
    如果您採用後者的方式來進入單機模式的話,您還需要執行底下的動作︰
    • fsck -p
      檢查檔案系統。如果您有絕對的自信且心臟夠強的話,您可以考慮不作這個動作。
    • mount -u /
      重新以可讀寫的方式來掛載 root slice。
    • mount -a -t ufs
      繼續掛載 root slice 之外的分割區(slice)。如果您全部只分割一個 / 的 slice 的話,可以省略。
    • swapon -a
      啟動所有於 /etc/fstab 中未加上『noauto』選項的 swap。
    當這些動作完成後,請依如下指令執行︰
    shell# cd /usr/src
    shell# make world

    這時您就會看到畫面上開始跑出一些訊息出來了,編譯的過程頗為耗時,通常大約需要四十幾分鐘以上,當然,這取決於您的 make.conf 設置參數不同以及機器配備等級不同而會有不同的編譯時間,總之是夠久的了,足夠您喝杯咖啡、看看報紙外加洗個澡了 ^_^

  • 多重模式︰
    如果您的機器配備等級不錯的話,可容許您於編譯系統時還可以進行其他作業,此時您可以選擇使用多重模式的編譯模式來編譯系統 -- 特別在您只有此部機器可作業的情況下。
    要使用多重模式的方式來編譯系統,您的現行系統版本最起碼是要 2.2.5 (含)的版本以上,因為自 2.2.5 版起,world 這個 target 已被分成了『buildworld』與『installworld』。
    也因為被分家了,所以我們能夠先在多重模式的作業環境下來進行編譯系統的動作,而在編譯系統的同時,我們還能夠進行其他作業,比如看看影片、打打文件等等,待整個系統編譯完成後,再切換至單機模式來進行安裝系統動作。
    聰明的您此刻應該已知道該如何來下指令了。沒錯,正是如下的步驟︰
    shell# cd /usr/src
    shell# make buildworld

    在 make buildworld 的指令中,我們還可以用個 -jx 的選項來指定最多可同時執行幾個 make 程序,其中 x 是以阿拉伯數字的格式,如 make -j4 buildworld
    一般來說這是給多顆 CPU 機器使用的,但是自從編譯動作受限於 I/O 頻頸大於 CPU 頻頸之後,在單顆 CPU 機器中,也開始流行使用這個編譯選項了。
    在只有一顆 CPU 的機器中,您可以使用 make -j4 buildworld 來進行編譯,make 將會以 4 個編譯程序來同時進行系統原始碼的編譯工作。根據 mail list 中的討論顯示,使用 -j4 選項,將可獲得最佳的編譯效能 -- 針對單顆 CPU 而言。如果您擁有多顆 CPU 的機器的話,您可以試著使用 -j6 ~ -j10 的選項來看看編譯效能如何。
    如果一切順利的話,您將可成功的編譯好系統 -- 在一段不算長的等待時間之後。此時請先將您手邊的工作暫告一個段落,以便切換到單機模式來進行系統安裝作業︰

    shell# shutdown now
    shell# cd /usr/src
    shell# make installworld
    在這兒有個重點您必需掌握到,就是您於 buildworld 下了什麼參數,那麼在 installworld 時就需同步的給予相同參數,但是 -j 選項則永遠不需要於 installworld 中使用。如︰
    於 buildworld 中使用了如下指令︰
    make -j4 buildworld -DNOPROFILE -DNOGAMES
    於 installworld 則需使用如下指令︰
    make installworld -DNOPROFILE -DNOGAMES

    除了 -jx 的這個選項之外,其餘所有於 buildworld 加入的使用參數,皆需於 installworld 中也加入使用才行,不然您將會於 installworld 時造成失敗。

如果您希望將 make 的輸出結果給存到另一個檔案中,以便於編譯失敗時偵錯或求助的話,您可以使用 script 這個指令來全程錄像,當編譯完成之後,您只需下達 exit 指令,即可停止 script 錄像的動作。如下︰
shell# script /root/mkw.out
# 表示開始錄影,錄影的結果將存放於 /root/mkw.out 檔案中
shell# make buildworld
........ 編譯訊息 ........
........ 編譯完成 ........
shell# exit
# 表示停止錄影

在編譯完系統且重新安裝好新版本系統後,接下來就需要更新 /etc/ 目錄下的設置檔了,因為不同的系統檔案版本,其對於所使用的設置檔皆有可能會有所改變,因此需要對其做編修,以免造成某服務無法正常執行甚至無法正常開機的窘相。
要更新 /etc/ 目錄下的設置檔,並不需要您一個一個檔案去做比對,FreeBSD 已為您準備好了 /usr/sbin/mergemaster 指令,以簡便許多於更新上的手續,它會自動幫您檢測某檔案是否有需要更新,如遇到需要更新的檔案,還會於螢幕秀出相異之處,讓管理者決定是要直接安裝新檔案,或是保留舊檔案,或是將兩者修改合併後再更新檔案。

您可以直接下達 mergemaster 指令,或是再加個 -i 的選項,讓 mergemaster 自動幫您將新版本系統中需要存在於 /etc/ 目錄下的設置檔,但現行系統版本中卻尚未存在的檔案給安裝進去,而不用於更新過程中還需回答安裝與否。在此建議您下達如下指令來進行 /etc/ 目錄的更新動作︰

shell# /usr/sbin/mergemaster -i

如果您想更加深入瞭解 mergemaster 的用法,請 man mergemaster(8)

當您於更新 /etc/ 目錄時所執行的 mergemaster 指令,正常來說都會順道幫您做好裝置節點更新的動作,除非在當時您選擇不做的選項,您才需要於此刻來手動進行這個工作。
如果您使用 devfs(5) 的話,您可以略過這一小節 -- FreeBSD 5.0 起的版本預設採用 devfs。
基於安全的考量,這一個動作將會需要滿多步驟來進行,如果您選擇自行更新的話,請務必仔細注意。
    每個指令範例中,凡以 shell# 開頭者,表示完整的一行,如有斷行係版面關係,請自行留意。

  • 首先,覆製 /var/tmp/root/dev/MAKEDEV 檔案到 /dev 目錄下。
    shell# cp /var/tmp/root/dev/MAKEDEV /dev

  • 再來,做一份 /dev 的檔案清單。裡面要包含權限、擁有者、major number、minor number,但是不必包含時間,最簡單的方法是使用 awk 把須要的資訊取出來。
    shell# cd /dev
    shell# ls -l | awk '{print $1, $2, $3, $4, $5, $6, $NF}' > /var/tmp/dev.out

  • 然後重新製作所有的裝置節點
    shell# sh MAKEDEV all

  • 再重新做一份 /dev 的檔案清單,但這次要存為不同的檔案 /var/tmp/dev2.out
    shell# ls -l | awk '{print $1, $2, $3, $4, $5, $6, $NF}' > /var/tmp/dev.out

  • 然後比對兩個檔案,仔細看看有沒有任何 device 沒有建立的,正常來說應該是所有該有的都有了,不過還是請您仔細留心比對一下。
    shell# diff /var/tmp/dev.out /var/tmp/dev2.out

  • 您應該會發現到,通常硬碟分割區 (slice) 的 device file 常會漏掉,當然,二話不說,您該為它建立相關的 device file。如︰
    shell# sh MAKEDEV sd0s1

  • 最後,是否該再建立其他額外的 device file 就因人而異了,請自行決定。

為了追求系統完整性,您或者會想順道更新 /stand/ 目錄下的檔案,裡面的檔案包含了 /stand/sysinstall 的 hard links,這檔案是屬靜態連結的,所以可以在沒有 mount 其它檔案系統的狀況下執行 (甚至是 /usr)。
shell# cd /usr/src/release/sysinstall
shell# make all install
這個步驟只是為了追求系統的完整產,所以您可以放心的省略過這個步驟。但若是版本大跳躍的情況下,比如 4.5 -> 4.7,建議您務必執行這個步驟。

在安裝設置好新版本的系統之後,您還需要重新編譯過您的系統核心,除了可以完全發揮新系統的威力外,事實上也是真的必要動作,因為有些記憶體結構也許會改變,像 ps、top 等指令,在尚未安裝新核心之前,是無法正常運作的。
相同的道理,新的核心在舊系統中也是有可能造成某些系統指令無法正常運作,最常見的自然還是與記憶體結構有關的指令了,如︰ps、top 等。有些人(比如早期的我 ^_^)因 make world 耗時過久,且有時可能因原始碼本身的關係或機器硬體裝置的不穩定,而造成 make world 不曾成功過,因而只顧著編譯更新核心,而忽略了系統本身,因此常會有部份系統指令無法正常運作,故在此提出,以供參考。

正常來說,您應該在 make world (或 make installworld)之後來編譯更新核心,然而您可能會想在安裝新版本系統之前先把新的核心安裝好 -- 事實上在 handbook 與 UPDATING 中也都是如此的安裝步驟,但有時您採用這種步驟時,很可能會遇到舊的 config 無法處理新的 kernel 原始碼 -- 雖然這種情況可說是很少遇到了。
如果您真的不幸遇到了這情況時,請採用舊的編譯核心方式,然後使用新的 config 來處理新的核心原始碼︰

shell# cd /sys/i386/conf
shell# /usr/obj/usr/src/usr.sbin/config KERNELNAME
shell# cd ../../compile/KERNELANME
shell# make depend && make all install clean

這樣將會以新的 config 來處理核心原始碼,但是卻也不是所有的情形都通用的,所以還是希望您能先進行 make world (或 make installworld) 之後,再來進行編譯安裝新核心的動作。
不過有時情況也實在是很難說,因為當版本跳躍過大時,整個系統結構可能會有極大的改變,而會需要以新版本的核心來進行 installworld。此時您就可能需要先行編譯安裝好新核心之後,並重新啟動系統進入單機模式下,再來進行 installworld。
總之,條條大路通羅馬,此路不通換他路。所有的方法其最終結果就是要達成目的,因此不要侷限於單一方法,要懂得變通喲 ^_^

提醒你︰
在您編譯新核心之前,請先查看 /sys/i386/conf/LINT 檔案,看看是否有什麼新功能可以加進您原有的核心配置檔中的。
shell# cd /usr/src
shell# make kernel KERNCONF=KERNELNAME

基於相同的理由,當安裝好新系統之後,第一次的核心編譯過程中,希望您不要省略了模組的編譯,省略編譯模組的部份,請留待下次編譯再省略。
同時,因為整個系統已更新過了,舊有的 kernel.GENERIC 核心檔也可能會與新系統發生水土不服的情況,因此也希望您能在編譯安裝好新核心之後,順道安裝新的 kernel.GENERIC 核心檔。
當然,這次就可以省略編譯模組的動作了,因為先前編譯新核心時已編譯安裝好新的核心模組了。

shell# cd /usr/src
shell# make kernel KERNCONF=GENERIC INSTKERNNAME=kernel.GENERIC -DNO_MODULES

經過數小時的奮鬥,現在終於大功告成了。
辛苦了 ^_^
現在該是重新開機的時候了,不用怕,勇敢的輸入 fastbootreboot 吧。
是生是死,在幾十來秒後便知分曉了!!


上一篇返回首頁目錄索引章節目錄回上一頁Page UP下一篇

最佳瀏灠環境︰Mozilla & 1024x768