linux配置、編譯內(nèi)核實用工具
Make
Make是一種幫助大型軟件工程的編譯工作實現(xiàn)自動化的編程語言。正確地使用Make可以大大減少因編譯程序而花費的時間,因為它可以消除不必要的再編譯。Make的基本設(shè)計思想是如果目標文件是在最近一次對源文件的修改之后編譯的,它就是“新的”,不需要重新編譯;如果最近一次對源文件的修改之后沒有及時更新目標文件,那么該目標文件就是“舊的”,需要重新編譯。為了理解Make如何執(zhí)行一個任務(wù),需要了解一些術(shù)語:
◆目標 需要執(zhí)行的一個任務(wù)。多數(shù)情況下它就是用戶要生成的文件的名字,但是它也可以僅是個任務(wù)的名字。
◆依賴關(guān)系 兩個目標之間相互依存的關(guān)系。如果修改目標B會造成目標A的修改,那么就說目標A依賴于目標B,B是A的先決條件。
◆變量 一種存儲臨時信息的載體。Make中使用的變量應(yīng)該加上括號,例如$(TEMP)。
◆命令 執(zhí)行任務(wù)時使用的指令,可以是一條、多條,甚至沒有。
◆規(guī)則 一條完整的規(guī)則具有以下格式:
目標(target) : 先決條件(prerequisites)
規(guī)則(command)
......
其中只有目標必須要有,其它成分可以沒有。一條完整的規(guī)則描述了編譯一個目標的方法和依賴關(guān)系,是Makefile中最重要的部分。
◆Makefile文件 描述如何生成一個或多個目標的文件。它列出目標依賴的各個文件,并提供正確編譯這些目標所需要的規(guī)則。
接下來以2.4.23的kbuild為例,簡要介紹一下內(nèi)核的構(gòu)建過程。首先,完整的內(nèi)核構(gòu)建過程由以下五種Makefile封裝。
1.根目錄Makefile
它是最重要的Makefile,定義所有與體系結(jié)構(gòu)無關(guān)的變量和目標。它讀取.config文件,并根據(jù)其信息最終生成vmlinux和modules。Make通過向下遞歸調(diào)用子目錄中的Makefile來編譯這兩個目標。
2.配置文件.config
執(zhí)行“make ”會在根目錄下生成該配置文件,其內(nèi)容記錄了具體的配置選擇,也可以將舊內(nèi)核的配置文件放在這里。
3.a(chǎn)rch/*/Makefile
這是與特定體系結(jié)構(gòu)相關(guān)的Makefile。它包含在根目錄下的Makefile中,為kbuild提供體系結(jié)構(gòu)的特定信息。
4.子目錄Makefiles
它們存在于每個子目錄下,大約有幾百個。它們接受來自上層Make傳遞下來的信息,并根據(jù)這些信息來構(gòu)造一個需要編譯的文件列表,并交由Rules.make處理。
5.Rules.make
幾乎每個子目錄Makefile都包含該Makefile。根據(jù)子目錄Makefiles構(gòu)建的文件列表,Make使用Rules.make定義的通用規(guī)則來編譯所有來自列表的源文件。
kbuild的執(zhí)行過程是:Make從根目錄Makefile開始執(zhí)行,從中獲得與體系結(jié)構(gòu)無關(guān)的變量和依賴關(guān)系,并同時從arch/*/Makefile中獲得體系特定的變量等信息,這些信息擴展了根目錄Makefile提供的變量。此時kbuild已經(jīng)擁有構(gòu)建內(nèi)核需要的所有變量和目標。然后,Make進入子目錄,把部分變量傳遞給子目錄Makefile。子目錄Makefile根據(jù)配置信息決定編譯哪些源文件,從而構(gòu)建出一個需要編譯的文件列表。最后,Rules.make根據(jù)其定義的編譯規(guī)則決定這些文件的編譯方式。
需要注意的是,由于Make的向下遞歸特性和無序性,其執(zhí)行過程并不完全遵守順序逐行執(zhí)行的規(guī)則,但無論Make的執(zhí)行有多復(fù)雜,也只分為兩個階段。第一個階段Make會讀取所有變量和分析所有目標的依賴關(guān)系,并最終建立一棵依賴關(guān)系樹。同時,所有的立即型變量(通過“:=”賦值)在這個過程中被擴展,就像C變量一樣。而在這個階段的最后,所有的延遲型變量才被擴展(通過“=”賦值)。這點需要格外注意。第二個階段Make會根據(jù)依賴關(guān)系樹執(zhí)行命令。
因此,一個目標和其先決條件的規(guī)則定義的順序是無所謂的,很可能一個目標的先決條件的規(guī)則定義在百行以后才出現(xiàn)。Make會耐心讀完所有的Makefile后分析得出依賴關(guān)系樹。
GCC
GCC是GNU的免費編譯程序,也是內(nèi)核惟一指定使用的編譯器。GCC在執(zhí)行一個完整的編譯任務(wù)時會經(jīng)過以下步驟:
◆預(yù)處理 GCC會調(diào)用cpp程序來分析各種宏指令,如#define、#if、#include等。
◆編譯 這一階段根據(jù)輸入文件產(chǎn)生匯編語言指令。由于通常情況下是立即調(diào)用匯編程序as,所以輸出一般不保存在文件中,可以使用-S選項強制輸出源程序的匯編版本。
◆匯編 這一階段將匯編語言源程序作為輸入,生成.o目標文件。
◆鏈接 這是最后一個階段。該階段中,各個.o模塊被鏈接在一起構(gòu)成可執(zhí)行文件。
as
用戶可以明確地要求使用as來直接處理匯編文件。as產(chǎn)生的目標文件可以分為文本段(.text)、數(shù)據(jù)段(.data)和未初始化數(shù)據(jù)段(.bss)。
ld
與as相似,用戶可以明確地要求使用ld鏈接程序?qū)讉€模塊組合成一個單獨的可執(zhí)行文件。其鏈接過程通常由一個叫l(wèi)d鏈接腳本的文件來描述。該腳本使用Linker Command Language編寫。使用“l(fā)d --verose”命令可以看到這個默認使用的ld鏈接腳本。
ar
ar是GNU的二進制文件處理程序,用于創(chuàng)建、修改及從歸檔文件中抽取文件。由它生成的.a歸檔文件實際上是一個包含許多可執(zhí)行二進制代碼子程序集合的庫文件。
RPMBuild
使用“make rpm”可以把內(nèi)核源代碼制作成RPM包。在此之前,kbuild會執(zhí)行“make spec”生成rpmbuild程序用到的spec文件,詳見“man rpmbuild”。
中間件
根目錄scripts下的各種腳本和C源文件都可以稱作中間件。它們并不是內(nèi)核組件的一部分,只是在kbuild執(zhí)行過程中的輔助程序。以split-include為例,講述配置文件的運作機理。
.config由關(guān)鍵字/值對組成,其內(nèi)容類似于:
CONFIG_MPENTIUMIII=y
# CONFIG_MPENTIUM4 is not set
CONFIG_REISERFS_FS=m
這些信息在執(zhí)行“make ”時自動生成。同時include/linux/autoconf.h依照.config的內(nèi)容生成。它的格式類似于:
#define CONFIG_MPENTIUMIII 1
#undef CONFIG_MPENTIUM4
#undefCONFIG_REISERFS_FS
#define CONFIG_REISERFS_FS_MODULE 1
對比一下不難發(fā)現(xiàn),include/linux/autoconf.h明確地洞悉了.config的意圖:哪些組件不編譯,哪些需要編譯進內(nèi)核,而哪些又要作為模塊來編譯?split-include根據(jù)include/linux/autoconf.h在include/config/下建立相關(guān)的目錄和.h文件。每個.h文件只包括include/linux/autoconf.h中的某一行,比如在配置內(nèi)核選項時支持NTFS文件系統(tǒng),并把它編譯進內(nèi)核,在.config中就會生成“CONFIG_NTFS_FS=y”,相應(yīng)地在include/linux/autoconf.h中會生成“#define CONFIG_NTFS_FS 1”一項。這樣,所有與NTFS文件系統(tǒng)相關(guān)的C源文件都會包含include/config/ntfs/fs.h頭文件。
如果以前編譯過內(nèi)核,并且沒有使用過“make mrproper”,.config、include/linux/autoconf.h和include/linux/config/就不會被刪除。這里涉及到新舊內(nèi)核的配置問題。一個全新的內(nèi)核代碼是未經(jīng)配置的。如果只在原內(nèi)核的功能基礎(chǔ)上增加對NTFS的支持,那么從頭開始配置無疑是浪費時間。可以繼續(xù)使用原內(nèi)核的.config文件,而所有的配置信息不會有任何更改,并且可以直接在原配置的基礎(chǔ)上增加新功能。
在復(fù)雜的情況下,保留的舊內(nèi)核配置信息還要與新的配置信息進行比較:哪些舊信息需要覆蓋,哪些需要保留?下面來看一下幾種可能的情況:
舊值保存在include/config/下的.h文件中,新值保存在新生成的include/linux/autoconf.h文件中。split-include的代碼不僅描述了如何處理這五種情況,還描述了include/config/下文件和子目錄的生成過程。
評論