我需要建立一個(gè)自設(shè)的內(nèi)核
英文版本由 RalphAngenendt 建立?,F(xiàn)在由 AlanBartlett 及 AkemiYagi 維護(hù)。
- 你肯定嗎?CentOS 被設(shè)計(jì)以一個(gè)完整的環(huán)境去運(yùn)作。如果你替換一個(gè)最要的元件,它很可能會(huì)影響系統(tǒng)其它部份的運(yùn)作。
-
你絕對(duì)肯定嗎?說(shuō)真的,99.9% 的用戶(hù)已經(jīng)不再須要重建自己的內(nèi)核:你可以單單建立一個(gè)模塊。若是這樣,你可參考「建立你自己的內(nèi)核模塊」。
- 你所需的功能是否由現(xiàn)有內(nèi)核的一個(gè)獨(dú)立模塊所提供?
-
你所需的功能是否由 CentOSPlus 軟件庫(kù)內(nèi)的 plus 內(nèi)核所提供?
- 最後警告……如果你損壞你的內(nèi)核或者系統(tǒng),你除了要承擔(dān)一切後果,你亦要獨(dú)個(gè)兒解決問(wèn)題,及埋怨自己令系統(tǒng)無(wú)法啟動(dòng)。
為 CentOS 建立自設(shè)的內(nèi)核有兩個(gè)方法:第一個(gè)是利用加了自設(shè)選項(xiàng)的 CentOS 源代碼;另一個(gè)是利用來(lái)自 Linux Kernel Archive的主流內(nèi)核源代碼。
這份教學(xué)文檔教授如何利用你自己的選項(xiàng)或改動(dòng),配合 CentOS 的源代碼來(lái)建立一個(gè)內(nèi)核。它主要是針對(duì) CentOS-5 而寫(xiě)成。請(qǐng)留意由 符號(hào)所標(biāo)示、關(guān)於在其它版本 CentOS 上建立內(nèi)核的備註。
(如果你希望建立一個(gè)主流的內(nèi)核,切勿依照 How To Compile A Kernel 內(nèi)的指引。這個(gè)網(wǎng)站不被認(rèn)可,因?yàn)樗虒?dǎo)的是不安全地以 root 建立內(nèi)核,因此方法本身有毛病。詳細(xì)理由請(qǐng)參閱 Building Source RPM as non-root under CentOS。建立主流內(nèi)核的一個(gè)良好參考指南是 Linux Kernel in a Nutshell。)
這些行動(dòng)都只供你個(gè)人使用。開(kāi)發(fā)小組並不支援自設(shè)的內(nèi)核,因?yàn)樗麄儫o(wú)法控制你的編譯環(huán)境、選取項(xiàng)目等。如果你選擇建立自設(shè)的內(nèi)核,當(dāng)有安全性更新、新發(fā)行、或任何須要進(jìn)行維護(hù)的情況出現(xiàn),你要獨(dú)力肩負(fù)起這個(gè)責(zé)任。 |
1. 編譯前的準(zhǔn)備
要成功地建立一個(gè)內(nèi)核,你須要安裝下列套件:
-
yum groupinstall "Development Tools" # 這樣做會(huì)確定你擁有編譯時(shí)所需的一切工具。
-
yum install ncurses-devel # 你必須這樣才能讓 make *config 這個(gè)指令正確地執(zhí)行。
-
yum install qt-devel # 如果你打算用 make xconfig 而不是 make gconfig 或 make menuconfig,才須要這樣做。
-
整個(gè)內(nèi)核的源代碼樹(shù)。 請(qǐng)跟從「我需要內(nèi)核代源碼」第 2 部份內(nèi)的指引。
如果你想加入任何內(nèi)核的修正,請(qǐng)於現(xiàn)在複製它們到 SOURCES 目錄內(nèi)。
2. 設(shè)定內(nèi)核
如何你在建立一個(gè) CentOS-4 內(nèi)核,請(qǐng)?jiān)谡萁虒W(xué)文檔內(nèi)用 2.6.9 取代 2.6.18,並且從這部份的目錄名稱(chēng)內(nèi)刪除 ".`uname -m`" 這個(gè)元件。
|
如果你不打算修改發(fā)行內(nèi)核的設(shè)定檔,你可以忽略這部份。你只需進(jìn)行最後一步: [user@host] $ cp ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.`uname -m`/configs/* ~/rpmbuild/SOURCES |
建立好編譯用的目錄後,現(xiàn)在是時(shí)候修改內(nèi)核的設(shè)定。請(qǐng)進(jìn)到 ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.`uname -m`/ 目錄,然後複製 ./configs/ 目錄內(nèi)的正確類(lèi)型設(shè)定檔(CentOS-5:base、xen、PAE 如果是 32 位元架構(gòu);CentOS-4:base、smp、xenU、hugemen 如果是 32 位元架構(gòu)、largesmp 如果是 64 位元架構(gòu)),或者複製現(xiàn)有內(nèi)核在 /boot/config-`uname -r` 的設(shè)定檔,成為這個(gè)目錄內(nèi)的 .config 檔。
請(qǐng)參考下面的範(fàn)例:
[user@host]$ cd ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.`uname -m` [user@host]$ cp configs/kernel-2.6.18-`uname -m`[-type].config .config
— 或 —
[user@host]$ cp /boot/config-`uname -r` .config
首先執(zhí)行 make oldconfig?,F(xiàn)在你應(yīng)該執(zhí)行 make menuconfig、make gconfig 或 make xconfig 來(lái)自訂內(nèi)核的設(shè)定。當(dāng)你完成後,請(qǐng)記得儲(chǔ)存你對(duì)設(shè)定的改動(dòng)。
|
如果你安裝了整個(gè)內(nèi)核的源代碼來(lái)建立一個(gè)內(nèi)核模塊,你應(yīng)該在這裡停手。請(qǐng)你現(xiàn)在便參考「建立你自己的內(nèi)核模塊」教學(xué)文檔。 |
接著,在你將設(shè)定檔複製回 configs/ 目錄前,請(qǐng)先將註釋了的硬件平臺(tái)(相等於 uname -i 指令的輸出)的一行加在設(shè)定檔的頂部。這個(gè)在 32 位元架構(gòu)上是 i386,在 64 位元架構(gòu)上是 x86_64。這個(gè)字串必須以 # 符號(hào)來(lái)註釋?zhuān)冶匦枋菣n案的頭一行。( 這一步無(wú)須在 CentOS-4 內(nèi)核上進(jìn)行。)
請(qǐng)?jiān)?.config 檔案的頂部加入以下一行:
# i386
— 或 —
# x86_64
現(xiàn)在將 .config 檔複製回 configs/ 目錄內(nèi)。這基本上與先前的複製指令剛剛相反:
[user@host]$ cp .config configs/kernel-2.6.18-`uname -m`-[類(lèi)型].config
最後一步就是將 configs/ 目錄內(nèi)的所有內(nèi)容複製到 ~/rpmbuild/SOURCES/ 目錄內(nèi)。
[user@host]$ cp configs/* ~/rpmbuild/SOURCES
3. 內(nèi)核的 ABI
CentOS 內(nèi)核的其中一個(gè)特色就是它的應(yīng)用程式二進(jìn)制介面(ABI)會(huì)在整個(gè)產(chǎn)品生效期內(nèi)保持一樣。kABI 維持不變的好處,就是外置的內(nèi)核模塊在建立時(shí)不必與內(nèi)核版本掛鈎 —— 因此它們不必在新內(nèi)核發(fā)行時(shí)被重新建立。這是追蹤 kABI 的內(nèi)核模塊套件的基礎(chǔ) —— 它們可以提供更新的驅(qū)動(dòng)程式及其它檔案系統(tǒng)等支援。
為了維繫 ABI 的一致性,原先的內(nèi)核的 ABI 會(huì)被記錄及儲(chǔ)存在一個(gè)檔案內(nèi)。這個(gè)檔案會(huì)在建立每個(gè)新內(nèi)核時(shí)用來(lái)檢查 kABI。如果新的內(nèi)核被設(shè)定或修改至一個(gè)地步令它的 ABI 與先前的有差別,編譯將會(huì)失敗,並且會(huì)有信息表示 kABI 的一致性已被破壞。這時(shí),內(nèi)核建立者有兩個(gè)選擇:(一)重新設(shè)定新的內(nèi)核,讓它的 kABI 與原有的能互相吻合,因而可繼續(xù)享受一致 ABI 所提供的好處;(二)在建立的過(guò)程中停止檢查 kABI。在這兩個(gè)選擇之間,前者較為可取,但有時(shí)後者是唯一可行的方法。
要停止檢查內(nèi)核的 ABI,你只須在 rpmbuild 指令行上加入一個(gè)選項(xiàng)及它的參數(shù):
--without kabichk
這本應(yīng)是一個(gè)簡(jiǎn)單的步驟。很不幸地,由 2.6.28-92.el5 的內(nèi)核起,kabitool 檔案內(nèi)的一個(gè)改動(dòng)揭露了內(nèi)核 spec 檔案裡一個(gè)潛在的錯(cuò)誤。這個(gè)錯(cuò)誤已經(jīng)穫得上游確認(rèn)(bz456765),並應(yīng)該會(huì)在第四個(gè)更新(CentOS 5.4)內(nèi)得到修正。
直至這個(gè)修正出現(xiàn),那些需要停止檢查 kABI 的內(nèi)核建立者必須在編輯內(nèi)核設(shè)定檔時(shí)執(zhí)行兩個(gè)額外的步驟。這兩個(gè)步驟已經(jīng)在這件教學(xué)文檔的下一個(gè)部份清楚列出來(lái)。
4. 更改內(nèi)核的 spec 檔案
|
這個(gè)部份所提及的行數(shù)只對(duì)應(yīng)現(xiàn)有 CentOS-5 內(nèi)核的 spec 檔案。 |
現(xiàn)在你須要更改內(nèi)核的 spec 檔案。
[user@host]$ cd ~/rpmbuild/SPECS [user@host SPECS]$ cp kernel-2.6.spec kernel-2.6.spec.distro [user@host SPECS]$ vi kernel-2.6.spec
以下這兩個(gè)改動(dòng)只適用於 >= 2.6.18-53.el5 的內(nèi)核。
在第 23 行,更改:
%define with_debug %{?_without_debug: 0} %{!?_without_debug: 1}
至:
%define with_debug 0
在第 29 行,更改:
%define with_debuginfo %{?_without_debuginfo: 0} %{!?_without_debuginfo: 1}
至:
%define with_debuginfo 0
在第 69 行,buildid 的定義本身是一個(gè)註釋。它必須被取消註釋及賦予一個(gè)數(shù)值,好避免與你現(xiàn)時(shí)安裝了的內(nèi)核互相抵觸。這將這行更改如下列樣子般:
%define buildid .your_identifier
|
"%" 與 "define" 這個(gè)字之間不可以有空格。 |
由第 6750 行起,有一段代碼需要被改為註釋。這段代碼是起頭是 #if a rhel kernel, apply the rhel config options。請(qǐng)?jiān)]釋這 17 行來(lái)建立自定的 CentOS-5 內(nèi)核( 這一步在建立自設(shè)的 CentOS-4 內(nèi)核時(shí)無(wú)須執(zhí)行。):
#if a rhel kernel, apply the rhel config options #%if 0%{?rhel} # for i in %{all_arch_configs} # do # mv $i $i.tmp # $RPM_SOURCE_DIR/merge.pl $RPM_SOURCE_DIR/config-rhel-generic $i.tmp > $i # rm $i.tmp # done #%ifarch ppc64 noarch # #CONFIG_FB_MATROX is disabled for rhel generic but needed for ppc64 rhel # for i in kernel-%{kversion}-ppc64.config # do # mv $i $i.tmp # $RPM_SOURCE_DIR/merge.pl $RPM_SOURCE_DIR/config-rhel-ppc64-generic $i.tmp > $i # rm $i.tmp # done #%endif #%endif
由於內(nèi)核 spec 檔案裡的錯(cuò)誤(它仍待上游去修正),你必須做以下兩個(gè)改動(dòng)。這個(gè)步驟只須在 >= 2.6.18-92.el5 而且停止檢查 kABI的內(nèi)核上進(jìn)行。詳情請(qǐng)見(jiàn)第 3 部份。
進(jìn)到第 7029。在那裡你會(huì)看見(jiàn)一段以 # Create the kABI metadata for use in packing 開(kāi)頭的代碼:
# Create the kABI metadata for use in packaging echo "**** GENERATING kernel ABI metadata ****" gzip -c9 < Module.symvers > $RPM_BUILD_ROOT/boot/symvers-$KernelVer.gz chmod 0755 %_sourcedir/kabitool if [ ! -e $RPM_SOURCE_DIR/kabi_whitelist_%{_target_cpu}$Flavour ]; then echo "**** No KABI whitelist was available during build ****" %_sourcedir/kabitool -b $RPM_BUILD_ROOT/$DevelDir -k $KernelVer -l $RPM_BUILD_ROOT/kabi_whitelist else cp $RPM_SOURCE_DIR/kabi_whitelist_%{_target_cpu}$Flavour $RPM_BUILD_ROOT/kabi_whitelist fi rm -f %{_tmppath}/kernel-$KernelVer-kabideps %_sourcedir/kabitool -b . -d %{_tmppath}/kernel-$KernelVer-kabideps -k $KernelVer -w $RPM_BUILD_ROOT/kabi_whitelist %if %{with_kabichk} echo "**** kABI checking is enabled in kernel SPEC file. ****" chmod 0755 $RPM_SOURCE_DIR/check-kabi if [ -e $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu}$Flavour ]; then cp $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu}$Flavour $RPM_BUILD_ROOT/Module.kabi $RPM_SOURCE_DIR/check-kabi -k $RPM_BUILD_ROOT/Module.kabi -s Module.symvers || exit 1 else echo "**** NOTE: Cannot find reference Module.kabi file. ****" fi %endif
請(qǐng)編輯原有的 23 行成為以下的 24 行:
# Create the kABI metadata for use in packaging echo "**** GENERATING kernel ABI metadata ****" gzip -c9 < Module.symvers > $RPM_BUILD_ROOT/boot/symvers-$KernelVer.gz %if %{with_kabichk} chmod 0755 %_sourcedir/kabitool if [ ! -e $RPM_SOURCE_DIR/kabi_whitelist_%{_target_cpu}$Flavour ]; then echo "**** No KABI whitelist was available during build ****" %_sourcedir/kabitool -b $RPM_BUILD_ROOT/$DevelDir -k $KernelVer -l $RPM_BUILD_ROOT/kabi_whitelist else cp $RPM_SOURCE_DIR/kabi_whitelist_%{_target_cpu}$Flavour $RPM_BUILD_ROOT/kabi_whitelist fi rm -f %{_tmppath}/kernel-$KernelVer-kabideps %_sourcedir/kabitool -b . -d %{_tmppath}/kernel-$KernelVer-kabideps -k $KernelVer -w $RPM_BUILD_ROOT/kabi_whitelist echo "**** kABI checking is enabled in kernel SPEC file. ****" chmod 0755 $RPM_SOURCE_DIR/check-kabi if [ -e $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu}$Flavour ]; then cp $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu}$Flavour $RPM_BUILD_ROOT/Module.kabi $RPM_SOURCE_DIR/check-kabi -k $RPM_BUILD_ROOT/Module.kabi -s Module.symvers || exit 1 else echo "**** NOTE: Cannot find reference Module.kabi file. ****" fi %endif touch %{_tmppath}/kernel-$KernelVer-kabideps
進(jìn)到第 7069 行。在那裡你會(huì)見(jiàn)一段以 # first copy everything 開(kāi)頭的代碼:
# first copy everything cp --parents `find -type f -name "Makefile*" -o -name "Kconfig*"` $RPM_BUILD_ROOT/lib/modules/$KernelVer/build cp Module.symvers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build cp Module.markers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build mv $RPM_BUILD_ROOT/kabi_whitelist $RPM_BUILD_ROOT/lib/modules/$KernelVer/build if [ -e $RPM_BUILD_ROOT/Module.kabi ]; then mv $RPM_BUILD_ROOT/Module.kabi $RPM_BUILD_ROOT/lib/modules/$KernelVer/build fi cp symsets-$KernelVer.tar.gz $RPM_BUILD_ROOT/lib/modules/$KernelVer/build # then drop all but the needed Makefiles/Kconfig files
請(qǐng)編輯原有的 10 行成為以下的 12 行:
# first copy everything cp --parents `find -type f -name "Makefile*" -o -name "Kconfig*"` $RPM_BUILD_ROOT/lib/modules/$KernelVer/build cp Module.symvers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build cp Module.markers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build %if %{with_kabichk} mv $RPM_BUILD_ROOT/kabi_whitelist $RPM_BUILD_ROOT/lib/modules/$KernelVer/build if [ -e $RPM_BUILD_ROOT/Module.kabi ]; then mv $RPM_BUILD_ROOT/Module.kabi $RPM_BUILD_ROOT/lib/modules/$KernelVer/build fi cp symsets-$KernelVer.tar.gz $RPM_BUILD_ROOT/lib/modules/$KernelVer/build %endif # then drop all but the needed Makefiles/Kconfig files
最後假若你有任何修正,你必須為每個(gè)修正增加兩行引用它們的語(yǔ)句。在第 3404 行,也就是接近修正申報(bào)的尾部,請(qǐng)以 40000 這數(shù)目開(kāi)始加入你的申報(bào),以免你的修正與 RHEL/CentOS 的內(nèi)核修正產(chǎn)生衝突。例如:
Patch40000: my-custom-kernel.patch
請(qǐng)?jiān)?6725 行之下加入應(yīng)用你的修正的語(yǔ)句。你只需要加入你先前申報(bào)的修正編號(hào),然後 rpmbuild 便會(huì)自動(dòng)地為你進(jìn)行修正。例如:
%patch40000 -p1
5. 編譯新內(nèi)核
開(kāi)始編譯:
[user@host SPECS]$ rpmbuild -bb --target=`uname -m` kernel-2.6.spec 2> build-err.log | tee build-out.log
你可以透過(guò) --with 及/或 --without 在 rpmbuild 指令內(nèi)加入些有用的選項(xiàng)。( 這些選項(xiàng)只由 >= 2.6.18-53.el5 的內(nèi)核提供。)
舉個(gè)例說(shuō):
[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --with baseonly kernel-2.6.spec 2> build-err.log | tee build-out.log
只會(huì)建立 base 內(nèi)核及相應(yīng)的 kernel-devel 套件。另一方面:
[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --with xenonly kernel-2.6.spec 2> build-err.log | tee build-out.log
只會(huì)建立 xen 內(nèi)核及相應(yīng)的 kernel-xen-devel 套件。至於:
[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --without up --without xen kernel-2.6.spec 2> build-err.log | tee build-out.log
只會(huì)建立 PAE 內(nèi)核及相應(yīng)的 kernel-PAE-devel 套件。
當(dāng)編譯完成後,你的自設(shè)內(nèi)核的 rpm 檔案可以在 ~/rpmbuild/RPMS/`uname -m`/ 目錄內(nèi)找到。切記要以 root 的身份,利用 rpm -ivh kernel-*.rpm 這個(gè)指令來(lái)安裝這些檔案。註:如果你建立了一個(gè)內(nèi)核比現(xiàn)時(shí)安裝的版本還要舊,你將會(huì)須要在 rpm 指令裡使用 --oldpackage 這個(gè)選項(xiàng)。
無(wú)論如何,切勿使用 rpm -Uvh 這個(gè)指令來(lái)安裝你的內(nèi)核,因?yàn)檫@樣做會(huì)更新(取替)你現(xiàn)時(shí)安裝了的版本。假如你自設(shè)的內(nèi)核有問(wèn)題,你將會(huì)無(wú)法返回原先能正常運(yùn)作的版本。
Translation of revision 111