Linux中國

Linux 內核動手編譯實用指南

一份讓你深入體驗最新 Linux 內核編譯過程的實操指南。

出於各種原因,自行編譯 Linux 內核可能引起你的興趣。這些原因可能包括但不限於:

  • 測試一個比你目前的 Linux 發行版更新的內核版本
  • 採用一組不同的配置選項、驅動來構建內核
  • 學習者的好奇心 ?

此指南將一步步指導你如何親自編譯 Linux 內核,包括你該運行哪些命令,為什麼運行這些命令以及這些命令的執行效果。本文篇幅較長,所以請做好準備!

? 諸如 Ubuntu 這樣的發行版提供了更簡單地安裝主線 Linux 內核的方式。但本教程目標是從源碼手動完成所有工作。此教程需要你付出時間、耐心以及豐富的 Linux 命令行使用經驗。本文更注重親身實踐的體驗。不管怎麼說,我仍建議你在虛擬機或備用系統中嘗試此冒險,而非在你的主系統上進行。

前置準備

在軟體領域,構建任何事物都有兩個基本要求:

  1. 源代碼
  2. 構建依賴

因此,作為預備環節,我們需要下載 Linux 內核的源碼壓縮包,並安裝一些能讓我們成功構建 Linux 內核的依賴項。

Linux 版本導覽

在任何時刻,Freax Linux 內核都有四種「版本」。

Linux 的這些 「版本」,按照開發流程的順序是:

  1. linux-next 樹: 所有準備合併到 Linux 代碼庫的代碼首先被合併到 linux-next 樹。它代表的是 Linux 內核最新也是「最不穩定」的狀態。大多數 Linux 內核開發者和測試人員使用這個來提高代碼質量,為 Linus Torvalds 的後續提取做準備。請謹慎使用!
  2. 發布候選版(RC) / 主線版: Linus 從 linux-next 樹抽取代碼並創建一個初始發布版本。這個初始發布版本的測試版稱為 RC( 發布候選 Release Candidate )版本。一旦 RC 版本發布,Linus 只會接受對它的錯誤修復和性能退化相關的補丁。基礎這些反饋,Linus 會每周發布一個 RC 內核,直到他對代碼感到滿意。RC 發行版本的標識是 -rc 後綴,後面跟一個數字。
  3. 穩定版: 當 Linus 覺得最新的 RC 版本已穩定時,他會發布最終的「公開」版本。穩定發布版將會維護幾周時間。像 Arch Linux 和 Fedora Linux 這樣的前沿 Linux 發行版會使用此類版本。我建議你在試用 linux-next 或任何 RC 版本之前,先試一試此版本。
  4. LTS 版本: 每年最後一個穩定版將會再維護 幾年。這通常是一個較舊的版本,但它會 會積極地維護並提供安全修復。Debian 的穩定版本會使用 Linux 內核的 LTS 版版本。

若想了解更多此方面的知識,可參閱 官方文檔

本文將以當前可用的最新穩定版為例,編寫此文時的 Linux 內核版本是 6.5.5

系統準備

由於 Linux 內核使用 C 語言編寫,編譯 Linux 內核至少需要一個 C 編譯器。你的計算機上可能還需要其他一些依賴項,現在是安裝它們的時候了。

? 這個指南主要聚焦於使用 GNU C 編譯器(GCC)來編譯 Linux 內核。但在未來的文章中(可能會深入介紹 Rust 的支持),我可能會介紹使用 LLVM 的 Clang 編譯器作為 GCC 的替代品。

不過,請注意,MSVC 並不適用。儘管如此,我仍期待有微軟的員工為此發送修補程序集。我在瞎想啥?

對於 Arch Linux 以及其衍生版本的用戶,安裝命令如下:

sudo pacman -S base-devel bc coreutils cpio gettext initramfs kmod libelf ncurses pahole perl python rsync tar xz

對於 Debian 以及其衍生版本的用戶,安裝命令如下:

sudo apt install bc binutils bison dwarves flex gcc git gnupg2 gzip libelf-dev libncurses5-dev libssl-dev make openssl pahole perl-base rsync tar xz-utils

對於 Fedora 以及其衍生版本的用戶,安裝命令如下:

sudo dnf install binutils ncurses-devel 
    /usr/include/{libelf.h,openssl/pkcs7.h} 
    /usr/bin/{bc,bison,flex,gcc,git,gpg2,gzip,make,openssl,pahole,perl,rsync,tar,xz,zstd}

下載 Linux 內核源碼

請訪問 kernel.org,在頁面中尋找第一個 穩定 Stable 版本。你不會找不到它,因為它是最顯眼的黃色方框哦 ?

點擊訪問 kernel.org

通過點擊黃色的方框,你就可以下載 Tar 文件。同時,也別忘了下載相匹配的 PGP 簽名文件,稍後我們需要用到它來驗證 Tar 文件。它的擴展名為 .tar.sign

校驗 Tar 文件的完整性

你如何知道剛下載的 Tar 文件是否被損壞?對於個人來說,一個損壞的 Tar 文件只會浪費你的寶貴時間,如果你是在為一個組織工作,那麼可能會危及到組織的安全(這時你可能還有更大的問題需要擔憂,但我們並不想讓所有人都產生創傷後應激障礙!)。

為了驗證我們的 Tar 文件的完整性,我們需要先解壓它。目前,它是使用 XZ 壓縮演算法壓縮的。因此,我將使用 unxz 工具(其實就是 xz --decompress 的別名)來解壓 .tar.xz 格式的壓縮文件。

unxz --keep linux-*.tar.xz

解壓完成後,我們需要獲取 Linus Torvalds 和 Greg KH 使用的 GPG 公開密鑰。這些密鑰用於對 Tar 文件進行簽名。

gpg2 --locate-keys torvalds@kernel.org gregkh@kernel.org

你應該可以得到一個與我在我的電腦上看到的類似的結果:

$ gpg2 --locate-keys torvalds@kernel.org gregkh@kernel.org
gpg: /home/pratham/.gnupg/trustdb.gpg: trustdb created
gpg: key 38DBBDC86092693E: public key "Greg Kroah-Hartman <gregkh@kernel.org>" imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg: key 79BE3E4300411886: public key "Linus Torvalds <torvalds@kernel.org>" imported
gpg: Total number processed: 1
gpg:               imported: 1
pub   rsa4096 2011-09-23 [SC]
      647F28654894E3BD457199BE38DBBDC86092693E
uid           [ unknown] Greg Kroah-Hartman <gregkh@kernel.org>
sub   rsa4096 2011-09-23 [E]

pub   rsa2048 2011-09-20 [SC]
      ABAF11C65A2970B130ABE3C479BE3E4300411886
uid           [ unknown] Linus Torvalds <torvalds@kernel.org>
sub   rsa2048 2011-09-20 [E]

在導入 Greg 和 Linus 的密鑰後,我們可以使用 --verify 標誌來驗證 Tar 的完整性,操作如下:

gpg2 --verify linux-*.tar.sign

如果驗證成功,你應該會看到如下的輸出信息:

$ gpg2 --verify linux-*.tar.sign
gpg: assuming signed data in &apos;linux-6.5.5.tar&apos;
gpg: Signature made Saturday 23 September 2023 02:46:13 PM IST
gpg:                using RSA key 647F28654894E3BD457199BE38DBBDC86092693E
gpg: Good signature from "Greg Kroah-Hartman <gregkh@kernel.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 647F 2865 4894 E3BD 4571  99BE 38DB BDC8 6092 693E

務必查看是否存在 gpg: Good signature 的提示,然後再繼續!

? 你可以忽略以下警告:WARNING: This key is not certified with a trusted signature! There is no indication that the signature belongs to the owner.

我們已根據 Linus 和 Greg 的郵件地址獲取了公開密鑰,並無需對此警告感到擔憂。

解壓 Tar 文件

如果你順利的進行到這裡,意味著你的 Tar 文件完整性檢查已經成功完成。接下來,我們將從 Tar 文件中解壓出 Linux 內核的源碼。

The &quot;TAR&quot; xkcd comic: https://xkcd.com/1168/

這個步驟十分簡單,只需對 Tar 文件執行 tar -xf 命令,如下:

tar -xf linux-*.tar

在這裡,-x 選項表示解壓,-f 選項則用來告訴 Tar 文件的文件名。

這個解壓過程可能需要幾分鐘時間,你可以先放鬆,耐心等待一下。

配置 Linux 內核

Linux 內核的構建過程會查找 .config 文件。顧名思義,這是一個配置文件,用於指定 Linux 內核的所有可能的配置選項。這是必需的文件。

獲取 Linux 內核的 .config 文件有兩種方式:

  1. 使用你的 Linux 發行版的配置作為基礎(推薦做法
  2. 使用默認的,通用的配置

? 也有第三種方法,也就是從零開始,手動配置每一個選項,但注意,這需要配置超過 12,000 個選項。並不推薦這種方式,因為手動配置所有選項將花費大量的時間,並且你還需要理解每個啟用和禁用選項的含義。

使用發行版提供的配置

使用你的 Linux 發行版提供的配置是一個安全的選擇。 如果你只是跟隨這個指南測試一個不是你的發行版提供的新內核,那麼這就是推薦的方式。

你的 Linux 發行版的 Linux 內核配置文件會在以下兩個位置之一:

  • 大多數 Linux 發行版,如 Debian 和 Fedora 及其衍生版,將會把它存在 /boot/config-$(uname -r)
  • 一些 Linux 發行版,比如 Arch Linux 將它整合在了 Linux 內核中。所以,可以在 /proc/config.gz 找到。

? 如果兩者都有,建議使用 /proc/config.gz。這是因為它在只讀文件系統中,所以是未被篡改的。

進入含有已經解壓出的 Tar 文件的目錄。

cd linux-*/

接著,複製你的 Linux 發行版的配置文件:

### Debian 和 Fedora 及其衍生版:
$ cp /boot/config-"$(uname -r)" .config

### Arch Linux 及其衍生版:
$ zcat /proc/config.gz > .config
更新配置文件

一旦完成這些步驟,接下來就需要「更新」配置文件了。因為你的發行版提供的配置很可能比你正在構建的 Linux 內核版本要舊。

? 這同樣適用於像 Arch Linux 和 Fedora 這樣前沿的 Linux 發行版。 它們並不會因為有新版本可用就立刻發布更新。他們會進行一些質量控制工作,這必然會花費些時間。因此,即便是你的發行版提供的最新內核,相較於你在 kernel.org 上獲取的版本也會滯後幾個小版本。

要更新一個已有的 .config 文件,我們使用 make 命令搭配 olddefconfig 參數。簡單解釋一下,這個命令的意思是使用 舊的、默認的、配置

這將使用「舊的配置文件」(當前保存為 .config,這是你發行版配置的一份直接副本),並檢查從上一版本以來 Linux 代碼庫中新加的任何配置選項。如果找到任何新的、未配置 的選項,該選項的默認配置值會被使用,並會對 .config 文件進行更新。

原來的 .config 文件將被重命名為 .config.old 進行備份,並將新的更改寫入至 .config 文件。

make olddefconfig

以下是我機器上的輸出:

$ file .config
.config: Linux make config build file, ASCII text

$ make olddefconfig
    HOSTCC  scripts/basic/fixdep
    HOSTCC  scripts/kconfig/conf.o
    HOSTCC  scripts/kconfig/confdata.o
    HOSTCC  scripts/kconfig/expr.o
    LEX     scripts/kconfig/lexer.lex.c
    YACC    scripts/kconfig/parser.tab.[ch]
    HOSTCC  scripts/kconfig/lexer.lex.o
    HOSTCC  scripts/kconfig/menu.o
    HOSTCC  scripts/kconfig/parser.tab.o
    HOSTCC  scripts/kconfig/preprocess.o
    HOSTCC  scripts/kconfig/symbol.o
    HOSTCC  scripts/kconfig/util.o
    HOSTLD  scripts/kconfig/conf
.config:8593:warning: symbol value &apos;m&apos; invalid for USB_FOTG210_HCD
.config:8859:warning: symbol value &apos;m&apos; invalid for USB_FOTG210_UDC
#
# configuration written to .config
#
針對 Debian 及其衍生版用戶

Debian 及其衍生版為內核模塊使用一個簽名證書。默認情況下,你的計算機並不包含這個證書。

我推薦關閉啟用模塊簽名的選項。具體如下所示:

./scripts/config --file .config --set-str SYSTEM_TRUSTED_KEYS &apos;&apos;
./scripts/config --file .config --set-str SYSTEM_REVOCATION_KEYS &apos;&apos;

如果你不這麼做,在後面你進行 Linux 內核構建時,可能會導致構建失敗。要注意這點。

使用自定義配置

如果你出於學習內核開發的目的學習如何構建 Linux 內核,那你應該這樣做。

? 請注意,偏離你的 Linux 發行版的配置可能無法在實體硬體上「正常」工作。問題可能是特定硬體無法工作、Linux 內核無法啟動等。

因此,我們只建議在虛擬機中使用。

你可以通過查看 make help 的輸出 來查看 所有 可用的選項,但我們主要關注三個 make 目標:

  • defconfig: 默認配置。
  • allmodconfig: 根據當前系統狀態,儘可能地把項目構建為可載入模塊(而非內建)。
  • tinyconfig: 極簡的 Linux 內核。

由於 tinyconfig 目標只會構建少數項目,構建時間將會縮短。我個人選擇它的原因主要有:

  1. 檢查我在代碼/工具鏈中做的修改是否正確,以及代碼是否可以編譯。
  2. 在虛擬機中只進行少數選項的測試。

? 在為 ARM 或 RISC-V 機器構建 Linux 內核時,你可能需要 DTB(設備樹的二進位文件)。使用 tinyconfig 目標將不會啟用構建 DTB 的選項,你的內核很可能無法啟動。

當然,你可以用 QEMU 在沒有任何 DTB 的情況下啟動 Linux 內核。但這篇文章並不會聚焦在此。或許你可以通過評論,讓我在之後的時間裡覆蓋這個話題 ?

除非你確切地知道自己在做什麼,否則你應當使用 defconfig 目標。 以下是我在我的電腦上運行的效果:

$ make defconfig
    HOSTCC  scripts/basic/fixdep
    HOSTCC  scripts/kconfig/conf.o
    HOSTCC  scripts/kconfig/confdata.o
    HOSTCC  scripts/kconfig/expr.o
    LEX     scripts/kconfig/lexer.lex.c
    YACC    scripts/kconfig/parser.tab.[ch]
    HOSTCC  scripts/kconfig/lexer.lex.o
    HOSTCC  scripts/kconfig/menu.o
    HOSTCC  scripts/kconfig/parser.tab.o
    HOSTCC  scripts/kconfig/preprocess.o
    HOSTCC  scripts/kconfig/symbol.o
    HOSTCC  scripts/kconfig/util.o
    HOSTLD  scripts/kconfig/conf
*** Default configuration is based on &apos;defconfig&apos;
#
# configuration written to .config
#

修改配置

無論你是使用 Linux 發行版的配置並更新它,還是使用 defconfig 目標創建新的 .config 文件,你都可能希望熟悉如何修改這個配置文件。最可靠的修改方式是使用 menuconfignconfig 目標。

這兩個目標的功能是相同的,只不過提供給你的界面有所不同。這是這兩者間唯一的區別。我個人更偏向於使用 menuconfig 目標,但近來我發現 nconfig 在搜索選項時似乎更具直觀性,所以我逐漸轉向使用它。

首先,帶著 menuconfig 目標運行 make 命令:

$ make menuconfig
    HOSTCC  scripts/kconfig/mconf.o
    HOSTCC  scripts/kconfig/lxdialog/checklist.o
    HOSTCC  scripts/kconfig/lxdialog/inputbox.o
    HOSTCC  scripts/kconfig/lxdialog/menubox.o
    HOSTCC  scripts/kconfig/lxdialog/textbox.o
    HOSTCC  scripts/kconfig/lxdialog/util.o
    HOSTCC  scripts/kconfig/lxdialog/yesno.o
    HOSTLD  scripts/kconfig/mconf

在此界面,你可以根據各選項的類型來進行切換操作。

有兩類可切換選項:

  • 布爾狀態選項:這類選項只能關閉([ ])或作為內建組件開啟([*])。
  • 三態選項:這類選項可以關閉(< >)、內建(<*>),或作為可載入模塊(<M>)進行構建。

想要了解更多關於某個選項的信息,使用上/下箭頭鍵導航至該選項,然後按 <TAB> 鍵,直至底部的 < Help > 選項被選中,然後按回車鍵進行選擇。此時就會顯示關於該配置選項的幫助信息。

在修改選項時請務必謹慎。

當你滿意配置後,按 <TAB> 鍵直到底部的 < Save > 選項被選中。然後按回車鍵進行選擇。然後再次按回車鍵(記住,此時不要更改文件名),就能將更新後的配置保存到 .config 文件中。

構建 Linux 內核

構建 Linux 內核實際上十分簡單。然而,在開始構建之前,讓我們為自定義內核構建添加一個標籤。我將使用字元串 -pratham 作為標籤,並利用 LOCALVERSION 變數來實施。你可以使用以下命令實現配置:

./scripts/config --file .config --set-str LOCALVERSION "-pratham"

這一命令將 .config 文件中的 CONFIG_LOCALVERSION 配置選項設為我在結尾指定的字元串,即 -pratham。當然,你也不必非得使用我所用的名字哦 ?

LOCALVERSION 選項可用於設置一個「本地」版本,它會被附加到通常的 x.y.z 版本方案之後,並在你運行 uname -r 命令時一併顯示。

由於我正在構建的是 6.5.5 版本內核,而 LOCALVERSION 字元串被設為 -pratham,因此,對我來說,最後的版本名將會是 6.5.5-pratham。這麼做的目的是確保我所構建的自定義內核不會與發行版所提供的內核產生衝突。

接下來,我們來真正地構建內核。可以用以下的命令完成此步驟:

make -j$(nproc) 2>&1 | tee log

這對大部分(99%)用戶來說已經足夠了。

其中的 -j 選項用於指定並行編譯任務的數量。而 nproc 命令用於返回可用處理單位(包括線程)的數量。因此,-j$(nproc) 其實意味著「使用我擁有的 CPU 線程數相同數量的並行編譯任務」。

2>&1 會將 STDOUT 和 STDIN 重定向到相同的文件描述符,並通過管道傳輸給 tee 命令,這會將輸出存儲在一個名為 log 的文件,並且在控制台列印出完全相同的文本。如果你在構建時遇到錯誤,並希望回顧日誌來檢查出了什麼問題,這將會十分有用。遇到那種情況,你只需要簡單執行 grep Error log 命令就能找到線索。

自定義 make 目標

在 Linux 內核的源文件夾中,make 命令有一些自定義的目標可供執行各種操作。這些主要作為開發者的參考。如果你的唯一目標是安裝一個比你當前發行版更新的 Linux 內核,那麼你完全可以跳過這部分內容 ?

構建目標

作為一名開發者,你可能只想構建 Linux 內核,或者只想構建模塊,或者只想構建設備樹二進位(DTB)。在這種情況下,你可以指定一個構建目標,然後 make 命令只會構建指定的項目,而不會構建其他的。

以下是一些構建目標:

  • vmlinux:純粹的 Linux 內核。
  • modules:可載入模塊。
  • dtbs:設備樹二進位文件(主要用於 ARM 和 RISC-V 架構)。
  • all:構建所有被標記了星號 * 的項目(從 make help 的輸出中可以查看)。

通常情況下,你並不需要指定構建目標,因為它們都已經在構建列表中。所列出的目標是在你只想要測試某一個構建目標,而不是其他目標時的情況。

依據你的 計算機架構,構建完成的 Linux 內核鏡像(存放在 /boot 目錄)的名稱會有所不同。

對於 x86_64,Linux 內核的默認鏡像名稱是 bzImage。因此,如果你只需要構建引導所需的 Linux 內核,你可以像下面這樣設定 bzImage 為目標:

### 對於 x86_64
$ make bzImage

「那麼如何在我的架構上找到用來調用 make 的目標名稱呢?」

有兩種方法。要麼你可以執行 make help 之後查找在 Architecture specific targets 下,第一個前面帶有星號 * 的選項。

或者,如果你希望自動完成,你可以利用 image_name 目標得到鏡像的完全路徑(相對路徑),選擇性地添加 -s 標誌來獲得有用的輸出。

以下是我擁有的三台電腦的輸出,一台是 x86_64,另一台是 AArch64,還有一台是 riscv

### x86_64
$ make -s image_name
arch/x86/boot/bzImage

### AArch64
$ make -s image_name
arch/arm64/boot/Image.gz

### RISC-V
$ make -s image_name
arch/riscv/boot/Image.gz

現在,要只構建 Linux 內核鏡像,你可以這樣進行:

make $(make -s image_name | awk -F &apos;/&apos; &apos;{print $4}&apos;)
清理目標

如果你需要清理構建產生的文件,你可以用以下的目標來實現你的需求:

  • clean:除了 .config 文件外,刪除幾乎所有其他內容。
  • mrproper:執行了 make clean 的所有操作外,還會刪除 .config 文件。
  • distclean:除了執行 make mrproper 的所有操作外,還會清理任何補丁文件。

安裝

一旦成功編譯了 Linux 內核,接下來就是啟動安裝一些東西的時候了。「一些 東西?」 沒錯,我們至少構建了兩種不同的東西,如果你使用的是 ARM 或 RISC-V 架構,那就有三種。我會在以下內容中詳細解釋。

? 雖然我將告訴你不同的安裝方式,尤其是關於如何改變默認安裝路徑的方法,但如果你不確定自己在做什麼,那麼我不建議你這麼做! 請慎重考慮,如果你決定走自定義的路線,那你需要自己負責後果。默認設置之所以存在,是因為它們有其特殊的原因 ?

安裝內核模塊

Linux 內核有部分在系統啟動時並非必需的。這些部分被構建為可載入模塊,即在需要時才進行載入和卸載。

所以,首先需要安裝這些模塊。這可以通過 modules_install 目標完成。必須使用 sudo,因為模塊會被安裝在 /lib/modules/<kernel_release>-<localversion> 這個需要 root 許可權的路徑下。

這個過程不僅會安裝內核模塊,還會對其進行簽名,所以可能需要一些時間。好消息是你可以通過之前提到的 -j$(nproc) 選項來並行執行安裝任務,這樣會快一些。?

sudo make modules_install -j$(nproc)

給開發者的提示: 你可以通過設定 INSTALL_MOD_PATH 變數來指定一個不同的路徑存放 Linux 模塊,而不用默認的 /lib/modules/<kernel_release>-<localversion>,具體如下:

   sudo make modules_install INSTALL_MOD_PATH=

另一個給開發者的提示: 你可以使用 INSTALL_MOD_STRIP 變數來決定是否需要剝離模塊的調試符號。如果未設定該變數,調試符號不會被剝離。當設為 1 時,符號信息將會被使用 --strip-debug 選項剝離,隨後該選項會傳遞給 strip(或者在使用 Clang 的時候傳遞給 llvm-strip)工具。

(可選)安裝 Linux 內核頭文件

如果你打算使用這個內核來支持樹外模塊,比如 ZFS 或英偉達 DKMS,或者打算嘗試自行編寫模塊,你可能會需要 Linux 內核提供的頭文件。

可以通過以下方式使用 headers_install 目標來安裝 Linux 內核頭文件:

sudo make headers_install

應使用 sudo 命令,因為這些頭文件會被安裝到 /usr 目錄。同時還會在 /usr 目錄內創建子目錄 include/linux,然後將頭文件安裝到 /usr/include/linux 內。

給開發者的提示: 通過設定 INSTALL_HDR_PATH 變數,你可以修改 Linux 內核頭文件的安裝路徑。

安裝 DTB(只針對 ARM 和 RISC-V)

如果你使用的是 x86_64 架構,那麼你可以跳過此步驟!

如果你針對 ARM 或者 RISC-V 構建了內核,那麼在運行 make 的過程中,設備樹的二進位文件可能已經被編譯出來了。你可以通過在 arch/<machine_architecture>/boot/dts 目錄查找 .dtb 文件來確認這一點。

這裡提供了一個快速檢查的技巧:

### 對於 AArch32
$ find arch/arm/boot/dts -name "*.dtb" -type f | head -n 1 > /dev/null && echo "DTBs for ARM32 were built"

### 對於 AArch64
$ find arch/arm64/boot/dts -name "*.dtb" -type f | head -n 1 > /dev/null && echo "DTBs for ARM64 were built"

### 對於 RISC-V
$ find arch/riscv/boot/dts -name "*.dtb" -type f | head -n 1 > /dev/null && echo "DTBs for RISC-V were built"

如果你看到出現 DTBs for <arch> were built 的消息,那麼你可以開始安裝 DTB。這可以通過 dtbs_install 目標來實現。

需要使用 sudo,因為它們會被安裝在 /boot/dtb-<kernel_release>-<localversion> 中,而這個目錄是由 root 所擁有的。

sudo make dtbs_install

給開發者的提示: 就像安裝模塊一樣,你可以使用 INSTALL_DTBS_PATH 變數指定一個自定義的路徑來安裝設備樹二進位文件。

安裝 Linux 內核

最後,我們來安裝 Linux 內核本身!這可以通過 install 目標來完成,就像這樣:

sudo make install

在這裡必須使用 sudo,因為 Linux 內核將被安裝在 /boot 目錄,而這個目錄不允許普通用戶寫入。

? 一般來講,install 目標也會更新引導載入程序,但是如果它沒有成功,那可能是不支持你使用的引導載入程序。如果你沒有使用 GRUB 作為你的引導載入程序,請一定要閱讀你引導載入程序的使用手冊 ?

給開發者的提示: 並不奇怪,INSTALL_PATH 變數被用來設定 Linux 內核的安裝位置,而非默認的 /boot 目錄。

針對 Arch Linux 用戶的說明

如果你嘗試執行了 make install 命令,可能已經注意到產生了錯誤。錯誤如下:

$ sudo make install
    INSTALL /boot
Cannot find LILO.

要在 Arch Linux 上實際完成 Linux 內核的安裝,我們需要手動複製 Linux 內核鏡像文件。別擔心,如果你使用的是 Arch Linux,手動操作應該是家常便飯了。( ͡° ͜ʖ ͡°)

可以使用以下命令完成這個步驟:

sudo install -Dm644 "$(make -s image_name)" /boot/vmlinuz-<kernel_release>-<localversion>

因為我編譯的是 6.5.5 版本的內核,所以我將會執行下面這條命令,你可以根據你的實際情況進行適當調整:

sudo install -Dm644 "$(make -s image_name)" /boot/vmlinuz-6.5.5-pratham

雖然不是必須的,但最好複製一份名為 System.map 的文件。既然你已經在操作了,一併也複製了 .config 文件吧 ?

sudo cp -vf System.map /boot/System.map-<kernel_release>-<localversion>
sudo cp -vf .config /boot/config-<kernel_release>-<localversion>
生成初始 RAM 磁碟

當你安裝 Arch Linux 時,可能已經了解過 mkinitcpio 這個工具。現在,我們將使用它來創建初始的 RAM 磁碟。

首先,我們需要創建一個預設文件。向 /etc/mkinitcpio.d/linux-<localversion>.preset 文件中添加以下內容,根據實際需要來替換 <kernel_release><localversion>

ALL_config="/etc/mkinitcpio.conf"
ALL_kver="/boot/vmlinuz-<kernel_release>-<localversion>"

PRESETS=(&apos;default&apos; &apos;fallback&apos;)

default_image="/boot/initramfs-<kernel_release>-<localversion>.img"
fallback_options="-S autodetect"

配置完成後,執行下面的命令來生成初始 RAM 磁碟:

sudo mkinitcpio -p linux-<localversion>

我自己的電腦上得到的輸出如下,你的結果應該會類似!

$ sudo mkinitcpio -p linux-pratham
==> Building image from preset: /etc/mkinitcpio.d/linux-pratham.preset: &apos;default&apos;
==> Using configuration file: &apos;/etc/mkinitcpio.conf&apos;
    -> -k /boot/vmlinuz-6.5.5-pratham -c /etc/mkinitcpio.conf -g /boot/initramfs-6.5.5-pratham.img
==> Starting build: &apos;6.5.5-pratham&apos;
    -> Running build hook: [base]
    -> Running build hook: [udev]
    -> Running build hook: [autodetect]
    -> Running build hook: [modconf]
    -> Running build hook: [kms]
    -> Running build hook: [keyboard]
==> WARNING: Possibly missing firmware for module: &apos;xhci_pci&apos;
    -> Running build hook: [keymap]
    -> Running build hook: [consolefont]
==> WARNING: consolefont: no font found in configuration
    -> Running build hook: [block]
    -> Running build hook: [filesystems]
    -> Running build hook: [fsck]
==> Generating module dependencies
==> Creating zstd-compressed initcpio image: &apos;/boot/initramfs-6.5.5-pratham.img&apos;
==> Image generation successful
==> Building image from preset: /etc/mkinitcpio.d/linux-pratham.preset: &apos;fallback&apos;
==> Using configuration file: &apos;/etc/mkinitcpio.conf&apos;
==> WARNING: No image or UKI specified. Skipping image &apos;fallback&apos;

初始 RAM 磁碟已成功生成,現在我們可以進入下一步,更新引導載入器!

更新 GRUB

一旦所有必要的文件已成功複製到其對應的位置,接下來,我們將進行 GRUB 的更新。

使用以下命令對 GRUB 引導載入器進行更新:

sudo grub-mkconfig -o /boot/grub/grub.cfg

? 如果你使用的引導載入器不是 GRUB,請參看 Arch Wiki 中相關的引導載入器文檔。

注意,更新 GRUB 並不會直接使新的內核版本設為默認啟動選項。在引導時,請在啟動菜單中手動選擇新的內核版本。

你可以通過選擇 Advanced options for Arch Linux 菜單,並在隨後的菜單中選擇 Arch Linux, with Linux <kernel_release>-<localversion> 來啟用新版的 Linux 內核。

重啟電腦

恭喜你!你已經完成了獲取 Linux 內核源代碼、進行配置、構建以及安裝等所有步驟。現在只需要通過重啟電腦並進入新構建和安裝的 Linux 內核,就可以開始享受你的努力成果了。

啟動時,請確保從引導載入器中選擇正確的 Linux 內核版本。系統啟動後,運行 uname -r 命令來確認你正在使用預期的 Linux 內核。

以下是我自己的電腦輸出的內容:

$ uname -r
6.5.5-pratham

是時候開始慶祝了! ?

卸載操作

? 提示:在刪除當前正在使用的內核版本之前,你應該首先切換至較舊的內核版本。

可能你的 Linux 發行版所使用的 Linux 內核版本就是你手動編譯的版本,或者你自行編譯了新的內核並注意到應卸載舊的內核以節省空間,於是你開始想如何才能卸載。當然,雖然我們無法簡單地運行 make uninstall 命令,但這並不代表沒有其他的方法!

我們清楚各個文件的安裝位置,因此刪除它們相對簡單。

### 刪除內核模塊
$ rm -rf /lib/modules/<kernel_release>-<localversion>

### 刪除設備樹二進位文件
$ rm -rf /boot/dtb-<kernel_release>-<localversion>

### 刪除 Linux 內核本身
$ rm -vf /boot/{config,System,vmlinuz}-<kernel_release>-<localversion>

總結

這個過程不是一次簡單的旅程,是吧?但是現在,我們終於抵達了終點。我們一起學習了手動編譯 Linux 內核的全過程,包括安裝依賴、獲取和驗證源碼、解壓源碼、配置 Linux 內核、構建內核以及安裝內核。

如果你喜歡這個詳細的步驟指南,請給我留言反饋。如果在操作過程中遇到問題,也歡迎提出,讓我知道!

(題圖:MJ/853481c5-87e3-42aa-8ace-e9ddfa232f75)

via: https://itsfoss.com/compile-linux-kernel/

作者:Pratham Patel 選題:lujun9972 譯者:ChatGPT 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
3
不錯
3
愛死了
3
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國