編譯Linux 2.6內核

編譯內核易如反掌。讓人歎爲觀止的是,這實際上比編譯和安裝像glibc這樣的系統級組伴還要簡單。2.6內核提供了一套新工具,使編譯內核更加容易,比早期發佈的內核有了長足的進步。

2.3.1 配置內核

因爲Linux源碼隨手可得,那就意味着在編譯它之前可以配置和定製。的確,你可以把自己需要的特定功能和驅動程序編譯進內核。在編譯內核之前,首先你必須配置它。由於內核提供了數不勝數的功能,支持了難以計數的硬件,因而有許多東西需要配置。可以配置的各種選項,以CONFIG_FEATURE形式表示,其前綴爲CONFIG。例如,對稱多處理器(SMP)的配置選項爲CONFIG_SMP。如果設置了該選項,則SMP啓用,否則,SMP不起作用。配置選項既可以用來決定哪些文件編譯進內核,也可以通過預處理命令處理代碼。

這些配置項要麼是二選一,要麼是三選一。二選一就是yes或no。比如CONFIG_PREEMPT就是二選一,表示內核搶佔功能是否開啓。三選一可以是yes、no或module。module意味着該配置項被選定了,但編譯的時候這部分功能的實現代碼是以模塊(一種可以動態安裝的獨立代碼段)的形式生成。在三選一的情況下,顯然yes選項表示把代碼編譯進主內核映像中,而不是作爲一個模塊。驅動程序一般都用三選一的配置項。

配置選項也可以是字符串或整數。這些選項並不控制編譯過程,而只是指定內核源碼可以訪問的值,一般以預處理宏的形式表示。比如,配置選項可以指定靜態分配數組的大小。

銷售商提供的內核,像Canonical的Ubuntu或者Red Hat的Fedora,他們的發佈版中包含了預編譯的內核,這樣的內核使得所需的功能得以充分地啓用,並幾乎把所有的驅動程序都編譯成模塊。這就爲大多數硬件作爲獨立的模塊提供了堅實的內核支持。但是,話又說回來,如果你是一個內核***,你應當編譯自己的內核,並按自己的意願決定包括或不包含哪一模塊。

內核提供了各種不同的工具來簡化內核配置。最簡單的一種是一個字符界面下的命令行工具:
$ make config

該工具會逐一遍歷所有配置項,要求用戶選擇yes、no或是module(如果是三選一的話)。由於這個過程往往要耗費掉很長時間,所以,除非你的工作是按小時計費的,否則應該多利用基於ncurse庫編制的圖形界面工具:
$ make menuconfig

或者,是用基於gtk+的圖形工具:
$ make gconfig

這三種工具將所有配置項分門別類放置,比如按“處理器類型和特點”。你可以按類移動、瀏覽內核選項,當然也可以修改其值。

這條命令會基於默認的配置爲你的體系結構創建一個配置:
$ make defconfig

儘管這些缺省值有點隨意性(在i386上,據說那就是Linus的配置),但是,如果你從未配置過內核,那它們會提供一個良好的開端。趕快行動吧,運行這條命令,然後回頭看看,確保爲你的硬件所配置的選項是啓用的。

這些配置項會被存放在內核代碼樹根目錄下的.config文件中。你很容易就能找到它(內核開發者差不多都能找到),並且可以直接修改它。在這裏面查找和修改內核選項也很容易。在你修改過配置文件之後,或者在用已有的配置文件配置新的代碼樹的時候,你應該驗證和更新配置:
$ make oldconfig

事實上,在編譯內核之前你都應該這麼做。

配置選項CONFIG_IKCONFIG_PROC把完整的壓縮過的內核配置文件存放在/proc/config.gz下,這樣當你編譯一個新內核的時候就可以方便地克隆當前的配置。如果你目前的內核已經啓用了此選項,就可以從/proc下複製出配置文件並且使用它來編譯一個新內核:
$ zcat /proc/config.gz > .config
$ make oldconfig

一旦內核配置好了(不論你是如何配置的),就可以使用一個簡單的命令來編譯它了:
$ make

這跟2.6以前的版本不同,你不用在每次編譯內核之間都運行make dep了—代碼之間的依賴關係會自動維護。你也無須再指定像老版本中bzImage這樣的編譯方式或獨立地編譯模塊,默認的Makefile規則會打點這一切。

2.3.2 減少編譯的垃圾信息

如果你想盡量少地看到垃圾信息,卻又不希望錯過錯誤報告與警告信息的話,你可以用以下命令來對輸出進行重定向:
$ make > .. /detritus

一旦你需要查看編譯的輸出信息,你可以查看這個文件。不過,因爲錯誤和警告都會在屏幕上顯示,所以你需要看這個文件的可能性不大。事實上,我只不過輸入如下命令:
$ make > /dev/null

就可把無用的輸出信息重定向到永無返回值的黑洞/dev/null。

2.3.3 衍生多個編譯作業

make程序能把編譯過程拆分成多個並行的作業。其中的每個作業獨立併發地運行,這有助於極大地加快多處理器系統上的編譯過程,也有利於改善處理器的利用率,因爲編譯大型源代碼樹也包括I/O等待所花費的時間(也就是處理器空下來等待I/O請求完成所花費的時間)。

默認情況下,make只衍生一個作業,因爲Makefiles常會出現不正確的依賴信息。對於不正確的依賴,多個作業可能會互相踩踏,導致編譯過程出錯。當然,內核的Makefiles沒有這樣的編碼錯誤,因此衍生出的多個作業編譯不會出現失敗。爲了以多個作業編譯內核,使用以下命令:
$ make –jn

這裏,n是要衍生出的作業數。在實際中,每個處理器上一般衍生出一個或者兩個作業。例如,在一個16核處理器上,你可以輸入如下命令:
$ make -j32 > /dev/null

利用出色的distcc或者 ccache工具,也可以動態地改善內核的編譯時間。

2.3.4 安裝新內核

在內核編譯好之後,你還需要安裝它。怎麼安裝就和體系結構以及啓動引導工具(boot loader)息息相關了—查閱啓動引導工具的說明,按照它的指導將內核映像拷貝到合適的位置,並且按照啓動要求安裝它。一定要保證隨時有一個或兩個可以啓動的內核,以防新編譯的內核出現問題。

例如,在使用grub的x86系統上,可能需要把arch/i386/boot/bzImage拷貝到/boot目錄下,像vmlinuz-version這樣命名它,並且編輯/etc/grub/grub.conf文件,爲新內核建立一個新的啓動項 。使用LILO啓動的系統應當編輯/etc/lilo.conf,然後運行lilo。

所幸,模塊的安裝是自動的,也是獨立於體系結構的。以root身份,只要運行:
% make modules_install
就可以把所有已編譯的模塊安裝到正確的主目錄/lib/modules下。

編譯時也會在內核代碼樹的根目錄下創建一個System.map文件。這是一份符號對照表,用以將內核符號和它們的起始地址對應起來。調試的時候,如果需要把內存地址翻譯成容易理解的函數名以及變量名,這就會很有用。

------------------------------

本文節選自《Linux內核設計與實現(原書第3版)》,作者:Robert Love(Linux核心***,Google公司資深軟件工程師,Android移動平臺內核開發團隊成員;曾就職於Novell公司,任職Linux桌面系統的首席架構師,以及MontaVista和Ximain公司內核開發工程師)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章