zh/HowTos/Custom Kernel

来源:百度文库 编辑:神马文学网 时间:2024/04/27 16:38:54

我需要建立一個自設的內核

英文版本由 RalphAngenendt 建立。現在由 AlanBartlett 及 AkemiYagi 維護。

Contents

  1. 編譯前的準備
  2. 設定內核
  3. 內核的 ABI
  4. 更改內核的 spec 檔案
  5. 編譯新內核
  • 你肯定嗎?CentOS 被設計以一個完整的環境去運作。如果你替換一個最要的元件,它很可能會影響系統其它部份的運作。
  • 你絕對肯定嗎?說真的,99.9% 的用戶已經不再須要重建自己的內核:你可以單單建立一個模塊。若是這樣,你可參考「建立你自己的內核模塊」。

  • 你所需的功能是否由現有內核的一個獨立模塊所提供?
  • 你所需的功能是否由 CentOSPlus 軟件庫內的 plus 內核所提供?

  • 最後警告……如果你損壞你的內核或者系統,你除了要承擔一切後果,你亦要獨個兒解決問題,及埋怨自己令系統無法啟動。

為 CentOS 建立自設的內核有兩個方法:第一個是利用加了自設選項的 CentOS 源代碼;另一個是利用來自 Linux Kernel Archive的主流內核源代碼。

這份教學文檔教授如何利用你自己的選項或改動,配合 CentOS 的源代碼來建立一個內核。它主要是針對 CentOS-5 而寫成。請留意由 符號所標示、關於在其它版本 CentOS 上建立內核的備註。

(如果你希望建立一個主流的內核,切勿依照 How To Compile A Kernel 內的指引。這個網站不被認可,因為它教導的是不安全地以 root 建立內核,因此方法本身有毛病。詳細理由請參閱 Building Source RPM as non-root under CentOS。建立主流內核的一個良好參考指南是 Linux Kernel in a Nutshell。)

這些行動都只供你個人使用。開發小組並不支援自設的內核,因為他們無法控制你的編譯環境、選取項目等。如果你選擇建立自設的內核,當有安全性更新、新發行、或任何須要進行維護的情況出現,你要獨力肩負起這個責任。


1. 編譯前的準備

要成功地建立一個內核,你須要安裝下列套件:

  • yum groupinstall "Development Tools" # 這樣做會確定你擁有編譯時所需的一切工具。

  • yum install ncurses-devel # 你必須這樣才能讓 make *config 這個指令正確地執行。

  • yum install qt-devel # 如果你打算用 make xconfig 而不是 make gconfigmake menuconfig,才須要這樣做。

  • 整個內核的源代碼樹。 請跟從「我需要內核代源碼」第 2 部份內的指引。

如果你想加入任何內核的修正,請於現在複製它們到 SOURCES 目錄內。

2. 設定內核

如何你在建立一個 CentOS-4 內核,請在整份教學文檔內用 2.6.9 取代 2.6.18,並且從這部份的目錄名稱內刪除 ".`uname -m`" 這個元件。

如果你不打算修改發行內核的設定檔,你可以忽略這部份。你只需進行最後一步: [user@host] $ cp ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.`uname -m`/configs/* ~/rpmbuild/SOURCES

建立好編譯用的目錄後,現在是時候修改內核的設定。請進到 ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.`uname -m`/ 目錄,然後複製 ./configs/ 目錄內的正確類型設定檔(CentOS-5:base、xen、PAE 如果是 32 位元架構;CentOS-4:base、smp、xenU、hugemen 如果是 32 位元架構、largesmp 如果是 64 位元架構),或者複製現有內核在 /boot/config-`uname -r` 的設定檔,成為這個目錄內的 .config 檔。

請參考下面的範例:

[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

首先執行 make oldconfig。現在你應該執行 make menuconfigmake gconfigmake xconfig 來自訂內核的設定。當你完成後,請記得儲存你對設定的改動。

如果你安裝了整個內核的源代碼來建立一個內核模塊,你應該在這裡停手。請你現在便參考「建立你自己的內核模塊」教學文檔。

接著,在你將設定檔複製回 configs/ 目錄前,請先將註釋了的硬件平台(相等於 uname -i 指令的輸出)的一行加在設定檔的頂部。這個在 32 位元架構上是 i386,在 64 位元架構上是 x86_64。這個字串必須以 # 符號來註釋,而且必需是檔案的頭一行。( 這一步無須在 CentOS-4 內核上進行。)

請在 .config 檔案的頂部加入以下一行:

# i386

— 或 —

# x86_64

現在將 .config 檔複製回 configs/ 目錄內。這基本上與先前的複製指令剛剛相反:

[user@host]$ cp .config configs/kernel-2.6.18-`uname -m`-[類型].config

最後一步就是將 configs/ 目錄內的所有內容複製到 ~/rpmbuild/SOURCES/ 目錄內。

[user@host]$ cp configs/* ~/rpmbuild/SOURCES

3. 內核的 ABI

CentOS 內核的其中一個特色就是它的應用程式二進制介面(ABI)會在整個產品生效期內保持一樣。kABI 維持不變的好處,就是外置的內核模塊在建立時不必與內核版本掛鈎 —— 因此它們不必在新內核發行時被重新建立。這是追踪 kABI 的內核模塊套件的基礎 —— 它們可以提供更新的驅動程式及其它檔案系統等支援。

為了維繫 ABI 的一致性,原先的內核的 ABI 會被記錄及儲存在一個檔案內。這個檔案會在建立每個新內核時用來檢查 kABI。如果新的內核被設定或修改至一個地步令它的 ABI 與先前的有差別,編譯將會失敗,並且會有信息表示 kABI 的一致性已被破壞。這時,內核建立者有兩個選擇:(一)重新設定新的內核,讓它的 kABI 與原有的能互相吻合,因而可繼續享受一致 ABI 所提供的好處;(二)在建立的過程中停止檢查 kABI。在這兩個選擇之間,前者較為可取,但有時後者是唯一可行的方法。

要停止檢查內核的 ABI,你只須在 rpmbuild 指令行上加入一個選項及它的參數:

--without kabichk

這本應是一個簡單的步驟。很不幸地,由 2.6.28-92.el5 的內核起,kabitool 檔案內的一個改動揭露了內核 spec 檔案裡一個潛在的錯誤。這個錯誤已經穫得上游確認(bz456765),並應該會在第四個更新(CentOS 5.4)內得到修正。

直至這個修正出現,那些需要停止檢查 kABI 的內核建立者必須在編輯內核設定檔時執行兩個額外的步驟。這兩個步驟已經在這件教學文檔的下一個部份清楚列出來。

4. 更改內核的 spec 檔案

這個部份所提及的行數只對應現有 CentOS-5 內核的 spec 檔案。

現在你須要更改內核的 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

以下這兩個改動只適用於 >= 2.6.18-53.el5 的內核。

在第 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 的定義本身是一個註釋。它必須被取消註釋及賦予一個數值,好避免與你現時安裝了的內核互相抵觸。這將這行更改如下列樣子般:

%define buildid .your_identifier

"%" 與 "define" 這個字之間不可以有空格。

由第 6750 行起,有一段代碼需要被改為註釋。這段代碼是起頭是 #if a rhel kernel, apply the rhel config options。請註釋這 17 行來建立自定的 CentOS-5 內核( 這一步在建立自設的 CentOS-4 內核時無須執行。):

#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

由於內核 spec 檔案裡的錯誤(它仍待上游去修正),你必須做以下兩個改動。這個步驟只須在 >= 2.6.18-92.el5 而且停止檢查 kABI的內核上進行。詳情請見第 3 部份。

進到第 7029。在那裡你會看見一段以 # Create the kABI metadata for use in packing 開頭的代碼:

    # 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

請編輯原有的 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

進到第 7069 行。在那裡你會見一段以 # first copy everything 開頭的代碼:

    # 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

請編輯原有的 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

最後假若你有任何修正,你必須為每個修正增加兩行引用它們的語句。在第 3404 行,也就是接近修正申報的尾部,請以 40000 這數目開始加入你的申報,以免你的修正與 RHEL/CentOS 的內核修正產生衝突。例如:

Patch40000: my-custom-kernel.patch

請在 6725 行之下加入應用你的修正的語句。你只需要加入你先前申報的修正編號,然後 rpmbuild 便會自動地為你進行修正。例如:

%patch40000 -p1

5. 編譯新內核

開始編譯:

[user@host SPECS]$ rpmbuild -bb --target=`uname -m` kernel-2.6.spec 2> build-err.log | tee build-out.log

你可以透過 --with 及/或 --without 在 rpmbuild 指令內加入些有用的選項。( 這些選項只由 >= 2.6.18-53.el5 的內核提供。)

舉個例說:

[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --with baseonly kernel-2.6.spec 2> build-err.log | tee build-out.log

只會建立 base 內核及相應的 kernel-devel 套件。另一方面:

[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --with xenonly kernel-2.6.spec 2> build-err.log | tee build-out.log

只會建立 xen 內核及相應的 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

只會建立 PAE 內核及相應的 kernel-PAE-devel 套件。

當編譯完成後,你的自設內核的 rpm 檔案可以在 ~/rpmbuild/RPMS/`uname -m`/ 目錄內找到。切記要以 root 的身份,利用 rpm -ivh kernel-*.rpm 這個指令來安裝這些檔案。註:如果你建立了一個內核比現時安裝的版本還要舊,你將會須要在 rpm 指令裡使用 --oldpackage 這個選項。

無論如何,切勿使用 rpm -Uvh 這個指令來安裝你的內核,因為這樣做會更新(取替)你現時安裝了的版本。假如你自設的內核有問題,你將會無法返回原先能正常運作的版本。

Translation of revision 111