本節書摘來自異步社群《linux核心修煉之道》一書中的第2章,第2.2節,作者:華清遠見嵌入式教育訓練中心 任橋偉著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視
linux核心修煉之道
2.2.1 準備工作
雖然與配置核心相比,編譯核心所做的工作要少得多,但是在正式編譯之前,我們仍需要做一些必要的準備。
1.需要了解的基礎知識
首先我們需要了解系統中與編譯過程有關的目錄及檔案。
/boot/vmlinuz-< version >:用于啟動的壓縮核心鏡像。
/boot/system.map-< version >:存儲核心符号表。
/boot/initrd.img-< version >:一個鏡像檔案,類似ramdisk(initrd的全稱就是initial ramdisk),它将一些驅動程式和指令工具打包到img裡,比如sisc_mod、ext3、sd_mod等子產品和insmod、nash等指令,然後在開機的時候在記憶體裡開辟一段區域,釋放到那裡運作。
它的作用是,在沒有mount根分區(/)以前,系統要執行一些操作,比如挂載scsi驅動,此時就把initrd釋放到記憶體裡,作一個虛拟的/,然後執行其根目錄下的腳本,運作insmod等指令加載子產品。
/boot/grub/menu.lst:grub的配置檔案(不同的發行版中它可能位于不同位置)。
/lib/modules/:該目錄包含了核心子產品(包括系統自帶的和自己編譯的)及其他檔案,不同的子目錄由核心版本号來區分。
/lib/modules/< kernel-version >/build/:存放編譯新子產品所需的檔案,包括了makefile、.config、module.symvers(子產品符号資訊)以及核心頭檔案等。
/lib/modules/< kernel-version >/kernel/:存放子產品的ko檔案。
/lib/modules//modules.alias:子產品别名定義,子產品加載工具使用它來加載相應的子產品。
/lib/modules/< kernel-version >/modules.dep:定義了子產品間的依賴關系。
/lib/modules/< kernel-version >/modules.symbols:辨別符号屬于哪個子產品。
2.下載下傳核心源碼壓縮包
需要注意下載下傳bz2格式的壓縮包時,需要安裝bzip2工具進行解壓。
3.擷取相關更新檔
如果需要的某些特性并沒有被現有核心支援,則需要去擷取相關的更新檔。比如,為了使核心支援圖形化的啟動界面,我們可能要用到bootsplash工具。bootsplash項目的網站<code>http://www.bootsplash.org/</code>上提供了針對很多核心版本的更新檔供下載下傳。
4.建構編譯環境
編譯核心需要用到一系列的工具,在編譯之前,我們需要確定它們已經被安裝。下面是一些debian和ubuntu發行版上用到的工具包。
modutils:子產品工具。
kernel-package:包括了make-kpkg等工具。
patch:如果不需要為核心打更新檔,可以不安裝patch工具包。
build-essential:提供了c/c++的編譯環境,包括了gcc、make等工具。
5.備份
當修改核心時,我們必須準備一個能夠啟動的備用核心。實作該目的的一種方式是通過配置linux引導程式(lilo或grub)以允許使用者選擇啟動的核心映象,其中之一是從未修改過的核心的備份。
2.2.2 如何為核心打更新檔
通過打更新檔的方法更新核心版本,可以不用下載下傳整個源代碼。針對每個核心版本的更新檔檔案可以在ftp.kernel.org上面獲得,我們的問題是應該選擇哪個更新檔檔案,一個更新檔又到底應該打在哪個版本的核心上。
下面的内容簡單介紹了如何應用與解除安裝更新檔,詳細的内容也可以檢視核心文檔document/applying-patchs。
1.什麼是更新檔
一個更新檔就是一個文本文檔,由diff工具建立,它存放了兩個不同版本的源代碼之間的差異。為了正确地應用一個更新檔,我們需要知道這個更新檔檔案是以哪個版本為基礎産生出來的,以及它将把目前的源代碼變化到什麼新的版本,簡單地說,就是需要清楚産生這個更新檔檔案的兩個源碼版本的情況。
2.如何打更新檔和解除安裝更新檔
patch工具可以用于打更新檔和解除安裝更新檔。核心的更新檔是相對于儲存核心源碼的父目錄而生成的,這就意味着,更新檔檔案中的檔案路徑包含了核心源碼存放目錄的名字(比如linux-2.6.23/,或者像是“a/”和“b/”之類的其他名字)。但是很可能我們本地系統上的核心源碼存放目錄和更新檔中不比對,為了解決這個問題,我們需要切換到自己的源碼目錄,并且在執行patch指令的時候加上“-p1”參數,這樣就會去掉更新檔檔案中路徑的第一個分量。比如:
為了解除安裝一個以前打上的更新檔,需要使用“-r”參數。
3.如何利用更新檔更新核心版本
考慮這樣的幾個場景:将核心從2.6.23更新到2.6.24;将核心從2.6.23.8更新到2.6.24.6;将核心從2.6.23.6更新到2.6.23.8。不管處于哪種場景,打更新檔時要謹記的一點是:核心的更新檔檔案都是以2.6.x(基礎穩定版basic stable,2.6.x.y是穩定版stable)為基礎釋出的。下面對這3種場景的打更新檔過程分别進行介紹。
(1)将核心從2.6.23更新到2.6.24。這種情況,可直接使用更新檔檔案patch-2.6.24。
因為下載下傳得到的更新檔檔案通常是使用gzip或bzip2壓縮的格式,是以使用前還要将其解壓生成patch-x.y.z檔案。不過,我們也可以不用解壓,使用下面的指令形式:
(2)将核心從2.6.23.8更新到2.6.24.6。這種情況下,我們需要将更新的過程分解為幾個步驟,首先将2.6.23.8退回到2.6.23,然後再更新到2.6.24,最後更新到2.6.24.6。
(3)将核心從2.6.23.6更新到2.6.23.8。這種情況下,我們同樣需要将更新過程分解,首先将2.6.23.6退回到2.6.23,然後再更新到2.6.23.8。
4.patch的替代工具
除了patch之外,也有其他的用來打更新檔的工具,比如interdiff、ketchup等。
2.2.3 編譯步驟
下面是針對2.6核心的通用的編譯步驟。
(1)下載下傳源碼并解壓。
雖然我們可以将核心源碼存放在任何自己找得到的地方,但通常還是會将核心源碼下載下傳到/usr/src目錄并解壓(linus本人說不要解壓到這個目錄)。
(2)如果需要的話,下載下傳更新檔。
(3)進入剛剛解壓的核心源碼目錄。
(4)如果需要的話,為核心打更新檔。
(5)配置核心。
(6)編譯核心。
(7)安裝核心子產品。将所有編譯得到的核心子產品複制到/lib/modules/< kernel-version >/目錄下面。
(8)安裝核心。
make install主要完成了3個工作。
複制生成的核心映像到/boot目錄。在核心編譯完成後,源碼樹目錄arch/i386/boot/中會生成一個bzimage檔案,該檔案被複制到/boot目錄并重命名為vmlinuz-2.6.23。
生成initrd-< kernel-version >.img檔案。
配置引導程式(grub或lilo)。
(9)重新開機進入新核心。
2.2.4 文檔的編譯
核心源碼樹的documentation/目錄下面有大量的文檔,它們是核心最好的參考資料,對于我們學習核心有着重要的意義。我們可以使用下面的一些指令生成指定格式的文檔。
執行make htmldocs/pdfdocs/psdocs之後,在documentation/docbook/目錄下,會生成一些很重要的文檔:
kernel-api:核心開發的api手冊。
kernel-locking:核心加鎖的howto文檔。
kernel-hacking:核心開發的一些注意事項。
usb:usb host端的api手冊。
gadget:usb device端的api手冊。
2.2.5 編譯小技巧
下面是一些核心編譯過程中可以使用的小技巧。
(1)屏蔽編譯資訊。
(2)加速編譯過程。
可以使用“-j< n >”參數,其中n = 2 * cpu的個數,對于一般的單cpu系統,通常用是使用“-j2”參數,為編譯過程配置設定兩個任務,這樣在進行磁盤i/o操作時候,cpu就不會空閑了。
(3)使用verbose模式,将每一步執行的指令都列印出來,并重定向到一個檔案中去,這樣以後可以友善地查找子產品之間的依賴關系。
(4)使用ccache提高編譯速度。使用ccache時,需要更改源碼樹根目錄下面的makefile檔案,在cc和hostcc變量的定義前添加ccache。