Linux 內核動手編譯實用指南
出於各種原因,自行編譯 Linux 內核可能引起你的興趣。這些原因可能包括但不限於:
- 測試一個比你目前的 Linux 發行版更新的內核版本
- 採用一組不同的配置選項、驅動來構建內核
- 學習者的好奇心 ?
此指南將一步步指導你如何親自編譯 Linux 內核,包括你該運行哪些命令,為什麼運行這些命令以及這些命令的執行效果。本文篇幅較長,所以請做好準備!
? 諸如 Ubuntu 這樣的發行版提供了更簡單地安裝主線 Linux 內核的方式。但本教程目標是從源碼手動完成所有工作。此教程需要你付出時間、耐心以及豐富的 Linux 命令行使用經驗。本文更注重親身實踐的體驗。不管怎麼說,我仍建議你在虛擬機或備用系統中嘗試此冒險,而非在你的主系統上進行。
前置準備
在軟體領域,構建任何事物都有兩個基本要求:
- 源代碼
- 構建依賴
因此,作為預備環節,我們需要下載 Linux 內核的源碼壓縮包,並安裝一些能讓我們成功構建 Linux 內核的依賴項。
Linux 版本導覽
在任何時刻,Freax Linux 內核都有四種「版本」。
Linux 的這些 「版本」,按照開發流程的順序是:
- linux-next 樹: 所有準備合併到 Linux 代碼庫的代碼首先被合併到 linux-next 樹。它代表的是 Linux 內核最新也是「最不穩定」的狀態。大多數 Linux 內核開發者和測試人員使用這個來提高代碼質量,為 Linus Torvalds 的後續提取做準備。請謹慎使用!
- 發布候選版(RC) / 主線版: Linus 從 linux-next 樹抽取代碼並創建一個初始發布版本。這個初始發布版本的測試版稱為 RC( 發布候選 )版本。一旦 RC 版本發布,Linus 只會接受對它的錯誤修復和性能退化相關的補丁。基礎這些反饋,Linus 會每周發布一個 RC 內核,直到他對代碼感到滿意。RC 發行版本的標識是
-rc
後綴,後面跟一個數字。 - 穩定版: 當 Linus 覺得最新的 RC 版本已穩定時,他會發布最終的「公開」版本。穩定發布版將會維護幾周時間。像 Arch Linux 和 Fedora Linux 這樣的前沿 Linux 發行版會使用此類版本。我建議你在試用 linux-next 或任何 RC 版本之前,先試一試此版本。
- 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,在頁面中尋找第一個 穩定 版本。你不會找不到它,因為它是最顯眼的黃色方框哦 ?
通過點擊黃色的方框,你就可以下載 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 'linux-6.5.5.tar'
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 內核的源碼。
這個步驟十分簡單,只需對 Tar 文件執行 tar -xf
命令,如下:
tar -xf linux-*.tar
在這裡,-x
選項表示解壓,-f
選項則用來告訴 Tar 文件的文件名。
這個解壓過程可能需要幾分鐘時間,你可以先放鬆,耐心等待一下。
配置 Linux 內核
Linux 內核的構建過程會查找 .config
文件。顧名思義,這是一個配置文件,用於指定 Linux 內核的所有可能的配置選項。這是必需的文件。
獲取 Linux 內核的 .config
文件有兩種方式:
- 使用你的 Linux 發行版的配置作為基礎(推薦做法)
- 使用默認的,通用的配置
? 也有第三種方法,也就是從零開始,手動配置每一個選項,但注意,這需要配置超過 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 'm' invalid for USB_FOTG210_HCD
.config:8859:warning: symbol value 'm' invalid for USB_FOTG210_UDC
#
# configuration written to .config
#
針對 Debian 及其衍生版用戶
Debian 及其衍生版為內核模塊使用一個簽名證書。默認情況下,你的計算機並不包含這個證書。
我推薦關閉啟用模塊簽名的選項。具體如下所示:
./scripts/config --file .config --set-str SYSTEM_TRUSTED_KEYS ''
./scripts/config --file .config --set-str SYSTEM_REVOCATION_KEYS ''
如果你不這麼做,在後面你進行 Linux 內核構建時,可能會導致構建失敗。要注意這點。
使用自定義配置
如果你出於學習內核開發的目的學習如何構建 Linux 內核,那你應該這樣做。
? 請注意,偏離你的 Linux 發行版的配置可能無法在實體硬體上「正常」工作。問題可能是特定硬體無法工作、Linux 內核無法啟動等。
因此,我們只建議在虛擬機中使用。
你可以通過查看 make help 的輸出 來查看 所有 可用的選項,但我們主要關注三個 make
目標:
defconfig
: 默認配置。allmodconfig
: 根據當前系統狀態,儘可能地把項目構建為可載入模塊(而非內建)。tinyconfig
: 極簡的 Linux 內核。
由於 tinyconfig
目標只會構建少數項目,構建時間將會縮短。我個人選擇它的原因主要有:
- 檢查我在代碼/工具鏈中做的修改是否正確,以及代碼是否可以編譯。
- 在虛擬機中只進行少數選項的測試。
? 在為 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 'defconfig'
#
# configuration written to .config
#
修改配置
無論你是使用 Linux 發行版的配置並更新它,還是使用 defconfig
目標創建新的 .config
文件,你都可能希望熟悉如何修改這個配置文件。最可靠的修改方式是使用 menuconfig
或 nconfig
目標。
這兩個目標的功能是相同的,只不過提供給你的界面有所不同。這是這兩者間唯一的區別。我個人更偏向於使用 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 '/' '{print $4}')
清理目標
如果你需要清理構建產生的文件,你可以用以下的目標來實現你的需求:
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=('default' 'fallback')
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: 'default'
==> Using configuration file: '/etc/mkinitcpio.conf'
-> -k /boot/vmlinuz-6.5.5-pratham -c /etc/mkinitcpio.conf -g /boot/initramfs-6.5.5-pratham.img
==> Starting build: '6.5.5-pratham'
-> 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: 'xhci_pci'
-> 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: '/boot/initramfs-6.5.5-pratham.img'
==> Image generation successful
==> Building image from preset: /etc/mkinitcpio.d/linux-pratham.preset: 'fallback'
==> Using configuration file: '/etc/mkinitcpio.conf'
==> WARNING: No image or UKI specified. Skipping image 'fallback'
初始 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
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive