Linux內(nèi)核Makefile文件 --譯自Linux2.6.x Kernel Makefiles http://bbs./htm_data/12/0510/100065.html 本文檔描述了linux內(nèi)核的makefile文件。 === 目錄 === 1 概述 === 2 角色分工 === 3 內(nèi)核編譯文件 --- 3.1 目標(biāo)定義 --- 3.2 內(nèi)嵌對象 - obj-y --- 3.3 可加載模塊 - obj-m --- 3.4 導(dǎo)出符號 --- 3.5 庫文件 - lib-y --- 3.6 目錄遞歸 --- 3.7 編譯標(biāo)記 --- 3.8 命令依賴 --- 3.9 依賴關(guān)系 --- 3.10 特殊規(guī)則 === 4 輔助程序 --- 4.1 簡單輔助程序 --- 4.2 組合輔助程序 --- 4.3 定義共享庫 --- 4.4 C++語言使用方法 --- 4.5 輔助程序編譯控制選項 --- 4.6 何時建立輔助程序 --- 4.7 使用hostprogs-$(CONFIG_FOO) === 5 編譯清除機制 === 6 體系Makefile文件 --- 6.1 變量設(shè)置 --- 6.2 增加預(yù)設(shè)置項 --- 6.3 目錄表 --- 6.4 引導(dǎo)映像 --- 6.5 編譯非內(nèi)核目標(biāo) --- 6.6 編譯引導(dǎo)映像命令 --- 6.7 定制編譯命令 --- 6.8 預(yù)處理連接腳本 --- 6.9 $(CC)支持功能 === 7 Kbuild變量 === 8 Makefile語言 === 9 Credits === 10 TODO === 1 概述 Makefile包括五部分: Makefile 頂層Makefile文件 .config 內(nèi)核配置文件 arch/$(ARCH)/Makefile 機器體系Makefile文件 scripts/Makefile.* 所有內(nèi)核Makefiles共用規(guī)則 kbuild Makefiles 其它makefile文件 通 過內(nèi)核配置操作產(chǎn)生.config文件,頂層Makefile文件讀取該文件的配置。頂層Makefile文件負(fù)責(zé)產(chǎn)生兩個主要的程序:vmlinux (內(nèi)核image)和模塊。頂層Makefile文件根據(jù)內(nèi)核配置,通過遞歸編譯內(nèi)核代碼樹子目錄建立這兩個文件。頂層Makefile文件文本一個名為 arch/$(ARCH)/Makefile的機器體系makefile文件。機器體系Makefile文件為頂層makefile文件提供與機器相關(guān)的 信息。每一個子目錄有一個makefile文件,子目錄makefile文件根據(jù)上級目錄makefile文件命令啟動編譯。這些makefile使用. config文件配置數(shù)據(jù)構(gòu)建各種文件列表,并使用這些文件列表編譯內(nèi)嵌或模塊目標(biāo)文件。scripts/Makefile.*包含了所有的定義和規(guī)則, 與makefile文件一起編譯出內(nèi)核程序。 === 2 角色分工 人們與內(nèi)核makefile存在四種不同的關(guān)系: *用戶* 用戶使用"make menuconfig"或"make"命令編譯內(nèi)核。他們通常不讀或編輯內(nèi)核makefile文件或其他源文件。 *普通開發(fā)者* 普通開發(fā)者維護設(shè)備驅(qū)動程序、文件系統(tǒng)和網(wǎng)絡(luò)協(xié)議代碼,他們維護相關(guān)子系統(tǒng)的makefile文件,因此他們需要內(nèi)核makefile文件整體性的一般知識和關(guān)于kbuild公共接口的詳細知識。 *體系開發(fā)者* 體系開發(fā)者關(guān)注一個整體的體系架構(gòu),比如sparc或者ia64。體系開發(fā)者既需要掌握關(guān)于體系的makefile文件,也要熟悉內(nèi)核makefile文件。 *內(nèi)核開發(fā)者* 內(nèi)核開發(fā)者關(guān)注內(nèi)核編譯系統(tǒng)本身。他們需要清楚內(nèi)核makefile文件的所有方面。 本文檔的讀者對象是普通開發(fā)者和系統(tǒng)開發(fā)者。 === 3 內(nèi)核編譯文件 內(nèi)核中大多數(shù)makefile文件是使用kbuild基礎(chǔ)架構(gòu)的makefile文件。本章介紹kbuild的makefile中的語法。 3.1節(jié)“目標(biāo)定義”是一個快速導(dǎo)引,后面各章有詳細介紹和實例。 --- 3.1 目標(biāo)定義 目標(biāo)定義是makefile文件的主要部分(核心)。這些目標(biāo)定義行定義了如何編譯文件,特殊的兼容選項和遞歸子目錄。 最簡單的makefile文件只包含一行: Example: obj-y += foo.o 這行告訴kbuild在該目錄下名為foo.o的目標(biāo)文件(object),foo.o通過編譯foo.c或者foo.S而得到。 如果foo.o編譯成一個模塊,則使用obj-m變量,因此常見寫法如下: Example: obj-$(CONFIG_FOO) += foo.o $(CONFIG_FOO)可以代表y(built-in對象)或m(module對象)。 如果CONFIG_FOO不是y或m,那么這個文件不會被編譯和鏈接。 --- 3.2 內(nèi)嵌對象 - obj-y makefile文件將為編譯vmlinux的目標(biāo)文件放在$(obj-y)列表中,這些列表依賴于內(nèi)核配置。 Kbuild編譯所有的$(obj-y)文件,然后調(diào)用"$(LD) -r"合并這些文件到一個built-in.o文件中。built-in.o經(jīng)過父makefile文件鏈接到vmlinux。$(obj-y)中的文件 順序很重要。列表中文件允許重復(fù),文件第一次出現(xiàn)將被鏈接到built-in.o,后續(xù)出現(xiàn)該文件將被忽略。 鏈接順序之所以重要是因為一些函數(shù)在內(nèi)核引導(dǎo)時將按照他們出現(xiàn)的順序被調(diào)用,如函數(shù)(module_init() / __initcall)。所以要牢記改變鏈接順序意味著也要改變SCSI控制器的檢測順序和重數(shù)磁盤。 例如: #drivers/isdn/i4l/Makefile # 內(nèi)核ISDN子系統(tǒng)和設(shè)備驅(qū)動程序Makefile # 每個配置項是一個文件列表 obj-$(CONFIG_ISDN) += isdn.o obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o --- 3.3 可加載模塊 - obj-m $(obj-m)表示對象文件(object files)編譯成可加載的內(nèi)核模塊。 一個模塊可以通過一個源文件或幾個源文件編譯而成。makefile只需簡單地它們加到$(obj-m)。 例如:#drivers/isdn/i4l/Makefile obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o 注意:在這個例子中$(CONFIG_ISDN_PPP_BSDCOMP)含義是‘m‘。 如果內(nèi)核模塊通過幾個源文件編譯而成,使用以上同樣的方法。 Kbuild需要知道通過哪些文件編譯模塊,因此需要設(shè)置一個$(<module_name>-objs)變量。 例如:#drivers/isdn/i4l/Makefile obj-$(CONFIG_ISDN) += isdn.o isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o 在這個例子中,模塊名isdn.o. Kbuild首先編譯$(isdn-objs)中的object文件,然后運行"$(LD) -r"將列表中文件生成isdn.o. Kbuild使用后綴-objs、-y識別對象文件。這種方法允許makefile使用CONFIG_符號值確定一個object文件是否是另外一個object的組成部分。 例如: #fs/ext2/Makefile obj-$(CONFIG_EXT2_FS) += ext2.o ext2-y := balloc.o bitmap.o ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o 在這個例子中,如果$(CONFIG_EXT2_FS_XATTR)表示‘y‘,則ext2.o只有xattr.o組成部分。 注意: 當(dāng)然,當(dāng)你將對象文件編譯到內(nèi)核時,以上語法同樣有效。因此,如果CONFIG_EXT2_FS=y,Kbuild將先編譯ext2.o文件,然后鏈接到built-in.o。 --- 3.4 導(dǎo)出符號目標(biāo) 在makefile文件中沒有特別導(dǎo)出符號的標(biāo)記。 --- 3.5 庫文件 - lib-y obj-*中的object文件用于模塊或built-in.o編譯。object文件也可能編譯到庫文件中--lib.a。 所有羅列在lib-y中的object文件都將編譯到該目錄下的一個單一的庫文件中。 包含在0bj-y中的object文件如果也列舉在lib-y中將不會包含到庫文件中,因為他們不能被訪問。但lib-m中的object文件將被編譯進lib.a庫文件。 注意在相同的makefile中可以列舉文件到buit-in內(nèi)核中也可以作為庫文件的一個組成部分。因此在同一個目錄下既可以有built-in.o也可以有l(wèi)ib.a文件。 例如:#arch/i386/lib/Makefile lib-y := checksum.o delay.o 這樣將基于checksum.o、delay.o創(chuàng)建一個lib.a文件。 對于內(nèi)核編譯來說,lib.a文件被包含在libs-y中。將“6.3 目錄表”。 lib-y通常被限制使用在lib/和arch/*/lib目錄中。 --- 3.6 目錄遞歸 makefile文件負(fù)責(zé)編譯當(dāng)前目錄下的目標(biāo)文件,子目錄中的文件由子目錄中的makefile文件負(fù)責(zé)編譯。編譯系統(tǒng)將使用obj-y和obj-m自動遞歸編譯各個子目錄中文件。 如果ext2是一個子目錄,fs目錄下的makefile將使用以下賦值語句是編譯系統(tǒng)編譯ext2子目錄。 例如: #fs/Makefile obj-$(CONFIG_EXT2_FS) += ext2/ 如果CONFIG_EXT2_FS設(shè)置成‘y(built-in)或‘m‘(modular),則對應(yīng)的obj-變量也要設(shè)置,內(nèi)核編譯系統(tǒng)將進入ext2目錄編譯文件。 內(nèi)核編譯系統(tǒng)只使用這些信息來決定是否需要編譯這個目錄,子目錄中makefile文件規(guī)定那些文件編譯為模塊那些是內(nèi)核內(nèi)嵌對象。 當(dāng)指定目錄名時使用CONFIG_變量是一種良好的做法。如果CONFIG_選項不為‘y‘或‘m‘,內(nèi)核編譯系統(tǒng)就會跳過這個目錄。 --- 3.7 編譯標(biāo)記 EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS 所有的EXTRA_變量只能使用在定義該變量后的makefile文件中。EXTRA_變量被makefile文件所有的執(zhí)行命令語句所使用。 $(EXTRA_CFLAGS)是使用$(CC)編譯C文件的選項。 例如: # drivers/sound/emu10k1/Makefile EXTRA_CFLAGS += -I$(obj) ifdef DEBUG EXTRA_CFLAGS += -DEMU10K1_DEBUG endif 定義這個變量是必須的,因為頂層makefile定義了$(CFLAGS)變量并使用該變量編譯整個代碼樹。 $(EXTRA_AFLAGS)是每個目錄編譯匯編語言源文件的選項。 例如: #arch/x86_64/kernel/Makefile EXTRA_AFLAGS := -traditional $(EXTRA_LDFLAGS)和$(EXTRA_ARFLAGS)用于每個目錄的$(LD)和$(AR)選項。 例如: #arch/m68k/fpsp040/Makefile EXTRA_LDFLAGS := -x CFLAGS_$@, AFLAGS_$@ CFLAGS_$@和AFLAGS_$@只使用到當(dāng)前makefile文件的命令中。 $(CFLAGS_$@)定義了使用$(CC)的每個文件的選項。$@部分代表該文件。 例如: # drivers/scsi/Makefile CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \ -DGDTH_STATISTICS CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM 這三行定義了aha152x.o、gdth.o和seagate.o文件的編譯選項。 $(AFLAGS_$@)使用在匯編語言代碼文件中,具有同上相同的含義。 例如: # arch/arm/kernel/Makefile AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional --- 3.9 依賴關(guān)系 內(nèi)核編譯記錄如下依賴關(guān)系: 1) 所有的前提文件(both *.c and *.h) 2) CONFIG_ 選項影響到的所有文件 3) 編譯目標(biāo)文件使用的命令行 因此,假如改變$(CC)的一個選項,所有相關(guān)的文件都要重新編譯。 --- 3.10 特殊規(guī)則 特殊規(guī)則使用在內(nèi)核編譯需要規(guī)則定義而沒有相應(yīng)定義的時候。典型的例子如編譯時頭文件的產(chǎn)生規(guī)則。其他例子有體系makefile編譯引導(dǎo)映像的特殊規(guī)則。特殊規(guī)則寫法同普通的Make規(guī)則。 Kbuild(應(yīng)該是編譯程序)在makefile所在的目錄不能被執(zhí)行,因此所有的特殊規(guī)則需要提供前提文件和目標(biāo)文件的相對路徑。 定義特殊規(guī)則時將使用到兩個變量: $(src): $(src)是對于makefile文件目錄的相對路徑,當(dāng)使用代碼樹中的文件時使用該變量$(src)。 $(obj): $(obj)是目標(biāo)文件目錄的相對路徑。生成文件使用$(obj)變量。 例如: #drivers/scsi/Makefile $(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl $(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl 這就是使用普通語法的特殊編譯規(guī)則。 目標(biāo)文件依賴于兩個前提文件。目標(biāo)文件的前綴是$(obj), 前提文件的前綴是$(src)(因為它們不是生成文件)。 === 4 輔助程序 內(nèi)核編譯系統(tǒng)支持在編譯(compliation)階段編譯主機可執(zhí)行程序。為了使用主機程序需要兩個步驟:第一個步驟使用hostprogs-y變量告 訴內(nèi)核編譯系統(tǒng)有主機程序可用。第二步給主機程序添加潛在的依賴關(guān)系。有兩種方法,在規(guī)則中增加依賴關(guān)系或使用$(always)變量。具體描述如下。 --- 4.1 簡單輔助程序 在一些情況下需要在主機上編譯和運行主機程序。下面這行告訴kbuild在主機上建立bin2hex程序。 例如: hostprogs-y := bin2hex Kbuild假定使用makefile相同目錄下的單一C代碼文件bin2hex.c編譯bin2hex。 --- 4.2 組合輔助程序 主機程序也可以由多個object文件組成。定義組合輔助程序的語法同內(nèi)核對象的定義方法。 $(<executeable>-objs)包含了所有的用于鏈接最終可執(zhí)行程序的對象。 例如: #scripts/lxdialog/Makefile hostprogs-y := lxdialog lxdialog-objs := checklist.o lxdialog.o 擴展名.o文件都編譯自對應(yīng)的.c文件。在上面的例子中checklist.c編譯成checklist.o,lxdialog.c編譯為lxdialog.o。最后兩個.o文件鏈接成可執(zhí)行文件lxdialog。 注意:語法<executable>-y不能用于定義主機程序。 --- 4.3 定義共享庫 擴展名為.so的對象是共享庫文件,并且是位置無關(guān)的object文件。內(nèi)核編譯系統(tǒng)提供共享庫使用支持,但使用方法有限制。在下面例子中l(wèi)ibkconfig.so庫文件被鏈接到可執(zhí)行文件conf中。 例如: #scripts/kconfig/Makefile hostprogs-y := conf conf-objs := conf.o libkconfig.so libkconfig-objs := expr.o type.o 共享庫文件需要對應(yīng)的-objs定義, 在上面例子中庫libkconfig由兩個對象組成:expr.o和type.o。expr.o和type.o將被編譯為位置無關(guān)代碼并被鏈接如libkconfig.so。共享庫不支持C++語言。 --- 4.4 C++語言使用方法 內(nèi)核編譯系統(tǒng)提供了對C++主機程序的支持以用于內(nèi)核配置,但不主張其它方面使用這種方法。 例如: #scripts/kconfig/Makefile hostprogs-y := qconf qconf-cxxobjs := qconf.o 在上面例子中可執(zhí)行文件由C++文件qconf.cc組成 - 通過$(qconf-cxxobjs)標(biāo)識。 如果qconf由.c和.cc文件混合組成,附加行表示這種情況。 例如: #scripts/kconfig/Makefile hostprogs-y := qconf qconf-cxxobjs := qconf.o qconf-objs := check.o --- 4.5 輔助程序編譯控制選項 當(dāng)編譯主機程序時仍然可以使用$(HOSTCFLAGS)設(shè)置編譯選項傳遞給$(HOSTCC)。這些選項將影響所有使用變量HOST_EXTRACFLAG的makefile創(chuàng)建的主機程序。 例如: #scripts/lxdialog/Makefile HOST_EXTRACFLAGS += -I/usr/include/ncurses 為單個文件設(shè)置選項使用下面方式: 例如: #arch/ppc64/boot/Makefile HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE) 也可以使用附加鏈接選項: 例如: #scripts/kconfig/Makefile HOSTLOADLIBES_qconf := -L$(QTDIR)/lib 當(dāng)鏈接qconf時將使用外部選項"-L$(QTDIR)/lib"。 --- 4.6 何時建立輔助程序 只有當(dāng)需要時內(nèi)核編譯系統(tǒng)才會編譯主機程序。有兩種方式: (1) 在特殊規(guī)則中作為隱式的前提需求 例如: #drivers/pci/Makefile hostprogs-y := gen-devlist $(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist ( cd $(obj); ./gen-devlist ) < $< 編譯目標(biāo)文件$(obj)/devlist.h需要先建立$(obj)/gen-devlist。注意在特殊規(guī)則中使用主機程序必須加前綴$(obj)。 (2) 使用$(always) 當(dāng)沒有合適的特殊規(guī)則可以使用,并且在進入makefile文件時就要建立主機程序,可以使用變量$(always)。 例如: #scripts/lxdialog/Makefile hostprogs-y := lxdialog always := $(hostprogs-y) 這樣就告訴內(nèi)核編譯系統(tǒng)即使沒有任何規(guī)則使用lxdialog也要編譯它。 --- 4.7 使用hostprogs-$(CONFIG_FOO) 在Kbuild文件中典型模式如下: 例如: #scripts/Makefile hostprogs-$(CONFIG_KALLSYMS) += kallsyms 對Kbuild來說‘y‘用于內(nèi)嵌對象‘m‘用于模塊。 因此如果config符號是‘m‘,編譯系統(tǒng)也將創(chuàng)建該程序。換句話說內(nèi)核編譯系統(tǒng)等同看待hostprogs-m和hostprogs-y。但如果不涉及到CONFIG符號僅建議使用hostprogs-y。 === 5 編譯清除機制 "make clean"命令刪除在編譯內(nèi)核生成的大部分文件,例如主機程序,列舉在 $(hostprogs-y)、$(hostprogs-m)、$(always)、$(extra-y)和$(targets)中目標(biāo)文件都將被刪除。 代碼目錄數(shù)中的"*.[oas]"、"*.ko"文件和一些由編譯系統(tǒng)產(chǎn)生的附加文件也將被刪除。 附加文件可以使用$(clean-files)進行定義。 例如: #drivers/pci/Makefile clean-files := devlist.h classlist.h 當(dāng)執(zhí)行"make clean"命令時, "devlist.h classlist.h"兩個文件將被刪除。內(nèi)核編譯系統(tǒng)默認(rèn)這些文件與makefile具有相同的相對路徑,否則需要設(shè)置以‘/‘開頭的絕對路徑。 刪除整個目錄使用以下方式: 例如: #scripts/package/Makefile clean-dirs := $(objtree)/debian/ 這樣就將刪除包括子目錄在內(nèi)的整個debian目錄。如果不使用以‘/‘開頭的絕對路徑內(nèi)核編譯系統(tǒng)見默認(rèn)使用相對路徑。 通常內(nèi)核編譯系統(tǒng)根據(jù)"obj-* := dir/"進入子目錄,但是在體系makefile中需要顯式使用如下方式: 例如: #arch/i386/boot/Makefile subdir- := compressed/ 上面賦值語句指示編譯系統(tǒng)執(zhí)行"make clean"命令時進入compressed/目錄。 在編譯最終的引導(dǎo)映像文件的makefile中有一個可選的目標(biāo)對象名稱是archclean。 例如: #arch/i386/Makefile archclean: $(Q)$(MAKE) $(clean)=arch/i386/boot 當(dāng)執(zhí)行"make clean"時編譯器進入arch/i386/boot并象通常一樣工作。arch/i386/boot中的makefile文件可以使用subdir-標(biāo)識進入更下層的目錄。 注意1: arch/$(ARCH)/Makefile不能使用"subdir-",因為它被包含在頂層makefile文件中,在這個位置編譯機制是不起作用的。 注意2: 所有列舉在core-y、libs-y、drivers-y和net-y中的目錄將被"make clean"命令清除。 === 6 體系Makefile文件 在開始進入各個目錄編譯之前,頂層makefile文件設(shè)置編譯環(huán)境和做些準(zhǔn)備工作。頂層makefile文件包含通用部分,arch/$(ARCH) /Makefile包含該體系架構(gòu)所需的設(shè)置。因此arch/$(ARCH)/Makefile會設(shè)置一些變量和少量的目標(biāo)。 當(dāng)編譯時將按照以下大概步驟執(zhí)行: 1) 配置內(nèi)核 => 產(chǎn)生 .config文件 2) 保存內(nèi)核版本到include/linux/version.h文件中 3) 符號鏈接include/asm to include/asm-$(ARCH) 4) 更新所有目標(biāo)對象的其它前提文件 - 附加前提文件定義在arch/$(ARCH)/Makefile文件中 5) 遞歸進入init-* core* drivers-* net-* libs-*中的所有子目錄和編譯所有的目標(biāo)對象 - 上面變量值都引用到arch/$(ARCH)/Makefile文件。 6) 鏈接所有的object文件生成vmlinux文件,vmlinux文件放在代碼樹根目錄下。 最開始鏈接的幾個object文件列舉在arch/$(ARCH)/Makefile文件的head-y變量中。 7) 最后體系makefile文件定義編譯后期處理規(guī)則和建立最終的引導(dǎo)映像bootimage。 - 包括創(chuàng)建引導(dǎo)記錄 - 準(zhǔn)備initrd映像和相關(guān)處理 --- 6.1 變量設(shè)置 LDFLAGS $(LD)一般選項 選項使用于鏈接器的所有調(diào)用中。通常定義emulation就可以了。 例如: #arch/s390/Makefile LDFLAGS := -m elf_s390 注意: EXTRA_LDFLAGS和LDFLAGS_$@可以進一步訂制使用選項,將第7章。 LDFLAGS_MODULE $(LD)鏈接模塊的選項 LDFLAGS_MODULE通常設(shè)置$(LD)鏈接模塊的.ko選項。 默認(rèn)為"-r"即可重定位輸出文件。 LDFLAGS_vmlinux $(LD)鏈接vmlinux選項 LDFLAGS_vmlinux定義鏈接最終vmlinux時鏈接器的選項。 LDFLAGS_vmlinux支持使用LDFLAGS_$@。 例如: #arch/i386/Makefile LDFLAGS_vmlinux := -e stext OBJCOPYFLAGS objcopy選項 當(dāng)使用$(call if_changed,objcopy)轉(zhuǎn)化a .o文件時,OBJCOPYFLAGS中的選項將被使用。 $(call if_changed,objcopy)經(jīng)常被用作為vmlinux產(chǎn)生原始的二進制文件。 例如: #arch/s390/Makefile OBJCOPYFLAGS := -O binary #arch/s390/boot/Makefile $(obj)/image: vmlinux FORCE $(call if_changed,objcopy) 在上面例子中$(obj)/image是vmlinux的二進制版本文件。$(call if_changed,xxx) 的使用方法見后。 AFLAGS $(AS)匯編選項 默認(rèn)值見頂層Makefile文件 針對每個體系需要另外添加和修改它。 例如: #arch/sparc64/Makefile AFLAGS += -m64 -mcpu=ultrasparc CFLAGS $(CC)編譯器選項 默認(rèn)值見頂層Makefile文件 針對每個體系需要另外添加和修改它。 通常CFLAGS變量值取決于內(nèi)核配置。 例如: #arch/i386/Makefile cflags-$(CONFIG_M386) += -march=i386 CFLAGS += $(cflags-y) 許多體系Makefiles文件動態(tài)啟動市場目標(biāo)機器上的C編譯器檢測支持的選項: #arch/i386/Makefile ... cflags-$(CONFIG_MPENTIUMII) += $(call cc-option,\ -march=pentium2,-march=i686) ... # Disable unit-at-a-time mode ... CFLAGS += $(call cc-option,-fno-unit-at-a-time) ... 第一個例子當(dāng)config選項是‘y‘時將被選中。 CFLAGS_KERNEL $(CC)編譯built-in對象的選項 $(CFLAGS_KERNEL)包含外部C編譯器選項編譯本地內(nèi)核代碼。 CFLAGS_MODULE $(CC)編譯模塊選項 $(CFLAGS_MODULE)包含外部C編譯器選項編譯可加載內(nèi)核代碼。 --- 6.2 增加預(yù)設(shè)置項 prepare: 這個規(guī)則用于列舉開始進入子目錄編譯前需要的前提文件。通常是些包含匯編常量的頭文件。 例如: #arch/s390/Makefile prepare: include/asm-$(ARCH)/offsets.h 在這個例子中include/asm-$(ARCH)/offsets.h將在進入子目錄前編譯。 詳見XXX-TODO文件描述了kbuild如何產(chǎn)生offset頭文件。 --- 6.3 目錄表 體系makefile文件和頂層makefile文件共同定義了如何建立vmlinux文件的變量。注意沒有體系相關(guān)的模塊對象定義部分:所有的模塊對象都是體系無關(guān)的。 head-y, init-y, core-y, libs-y, drivers-y, net-y $(head-y) 列舉首先鏈接到vmlinux的對象文件。 $(libs-y) 列舉了能夠找到lib.a文件的目錄。 其余的變量列舉了能夠找到內(nèi)嵌對象文件的目錄。 $(init-y) 列舉的對象位于$(head-y)對象之后。 然后是如下位置秩序: $(core-y), $(libs-y), $(drivers-y) 和 $(net-y)。 頂層makefile定義了所有同用目錄,arch/$(ARCH)/Makefile文件只需增加體系相關(guān)的目錄。 例如: #arch/sparc64/Makefile core-y += arch/sparc64/kernel/ libs-y += arch/sparc64/prom/ arch/sparc64/lib/ drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/ --- 6.4 引導(dǎo)映像 體系makefile文件定義了編譯vmlinux文件的目標(biāo)對象,將它們壓縮和封裝成引導(dǎo)代碼,并復(fù)制到合適的位置。這包括各種安裝命令。如何定義實際的目標(biāo)對象無法為所有的體系結(jié)構(gòu)提供標(biāo)準(zhǔn)化的方法。 附加處理過程常位于arch/$(ARCH)/下的boot/目錄。 內(nèi)核編譯系統(tǒng)無法在boot/目錄下提供一種便捷的方法創(chuàng)建目標(biāo)系統(tǒng)文件。因此arch/$(ARCH)/Makefile要調(diào)用make命令在 boot/目錄下建立目標(biāo)系統(tǒng)文件。建議使用的方法是在arch/$(ARCH)/Makefile中設(shè)置調(diào)用,并且使用完整路徑引用arch/$ (ARCH)/boot/Makefile。 例如: #arch/i386/Makefile boot := arch/i386/boot bzImage: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ 建議使用"$(Q)$(MAKE) $(build)=<dir>"方式在子目錄中調(diào)用make命令。 沒有定義體系目標(biāo)系統(tǒng)文件的規(guī)則,但執(zhí)行"make help"命令要列出所有目標(biāo)系統(tǒng)文件,因此必須定義$(archhelp)變量。 例如: #arch/i386/Makefile define archhelp echo ‘* bzImage - Image (arch/$(ARCH)/boot/bzImage)‘ endef 當(dāng)執(zhí)行不帶參數(shù)的make命令時,將首先編譯第一個目標(biāo)對象。在頂層makefile中第一個目標(biāo)對象是all:。 一個體系結(jié)構(gòu)需要定義一個默認(rèn)的可引導(dǎo)映像。 "make help"命令的默認(rèn)目標(biāo)是以*開頭的對象。 增加新的前提文件給all目標(biāo)可以設(shè)置不同于vmlinux的默認(rèn)目標(biāo)對象。 例如: #arch/i386/Makefile all: bzImage 當(dāng)執(zhí)行不帶參數(shù)的"make"命令時,bzImage文件將被編譯。 --- 6.5 編譯非內(nèi)核目標(biāo) extra-y extra-y定義了在當(dāng)前目錄下創(chuàng)建沒有在obj-*定義的附加的目標(biāo)文件。 在extra-y中列舉目標(biāo)是處于兩個目的: 1) 是內(nèi)核編譯系統(tǒng)在命令行中檢查變動情況 - 當(dāng)使用$(call if_changed,xxx)時 2) 內(nèi)核編譯系統(tǒng)知道執(zhí)行"make clean"命令時刪除哪些文件 例如: #arch/i386/kernel/Makefile extra-y := head.o init_task.o 上面例子extra-y中的對象文件將被編譯但不會練接到built-in.o中。 --- 6.6 編譯引導(dǎo)映像命令 Kbuild提供了一些編譯引導(dǎo)映像有用的宏。 if_changed if_changed是后面命令使用的基礎(chǔ)。 用法: target: source(s) FORCE $(call if_changed,ld/objcopy/gzip) 當(dāng)這條規(guī)則被使用時它將檢查哪些文件需要更新,或命令行被改變。后面這種情況將迫使重新編譯編譯選項被改變的執(zhí)行文件。使用if_changed的目標(biāo)對象必須列舉在$(targets)中,否則命令行檢查將失敗,目標(biāo)一直會編譯。 賦值給$(targets)的對象沒有$(obj)/前綴。 if_changed也可以和定制命令配合使用,見6.7"kbuild定制命令"。 注意: 一個常見錯誤是忘記了FORCE前導(dǎo)詞。 ld 鏈接目標(biāo)。常使用LDFLAGS_$@作為ld的選項。 objcopy 復(fù)制二進制文件。常用于arch/$(ARCH)/Makefile中和使用OBJCOPYFLAGS作為選項。 也可以用OBJCOPYFLAGS_$@設(shè)置附加選項。 gzip 壓縮目標(biāo)文件。使用最大壓縮算法壓縮目標(biāo)文件。 例如: #arch/i386/boot/Makefile LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext targets += setup setup.o bootsect bootsect.o $(obj)/setup $(obj)/bootsect: %: %.o FORCE $(call if_changed,ld) 在上面例子中有兩個可能的目標(biāo)對象,分別需要不同的鏈接選項。使用LDFLAGS_$@語法為每個目標(biāo)對象設(shè)置不同的鏈接選項。 $(targets)包含所有的目標(biāo)對象,因此內(nèi)核編譯系統(tǒng)知道所有的目標(biāo)對象并且將: 1) 檢查命令行的改變情況 2) 執(zhí)行make clean命令時刪除目標(biāo)對象 ": %: %.o"是簡寫方法,減寫setup.o和bootsect.o文件。 注意: 常犯錯誤是忘記"target :="語句,導(dǎo)致沒有明顯的原因目標(biāo)文件被重新編譯。 --- 6.7 定制編譯命令 當(dāng)執(zhí)行帶KBUILD_VERBOSE=0參數(shù)的編譯命令時命令的簡短信息會被顯示。要讓定制命令具有這種功能需要設(shè)置兩個變量: quiet_cmd_<command> - 將被顯示的內(nèi)容 cmd_<command> - 被執(zhí)行的命令 例如: # quiet_cmd_image = BUILD $@ cmd_image = $(obj)/tools/build $(BUILDFLAGS) \ $(obj)/vmlinux.bin > $@ targets += bzImage $(obj)/bzImage: $(obj)/vmlinux.bin $(obj)/tools/build FORCE $(call if_changed,image) @echo ‘Kernel: $@ is ready‘ 執(zhí)行"make KBUILD_VERBOSE=0"命令編譯$(obj)/bzImage目標(biāo)時將顯示: BUILD arch/i386/boot/bzImage --- 6.8 預(yù)處理連接腳本 當(dāng)編譯vmlinux映像時將使用arch/$(ARCH)/kernel/vmlinux.lds鏈接腳本。 相同目錄下的vmlinux.lds.S文件是這個腳本的預(yù)處理的變體。內(nèi)核編譯系統(tǒng)知曉.lds文件并使用規(guī)則*lds.S -> *lds。 例如: #arch/i386/kernel/Makefile always := vmlinux.lds #Makefile export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH) $(always)賦值語句告訴編譯系統(tǒng)編譯目標(biāo)是vmlinux.lds。$(CPPFLAGS_vmlinux.lds)賦值語句告訴編譯系統(tǒng)編譯vmlinux.lds目標(biāo)的編譯選項。 編譯*.lds時將使用到下面這些變量: CPPFLAGS : 定義在頂層Makefile EXTRA_CPPFLAGS : 可以設(shè)置在編譯的makefile文件中 CPPFLAGS_$(@F) : 目標(biāo)編譯選項。注意要使用文件全名。 --- 6.9 $(CC)支持功能 內(nèi)核可能會用不同版本的$(CC)進行編譯,每個版本有不同的性能和選項,內(nèi)核編譯系統(tǒng)提供基本的支持用于驗證$(CC)選項。$(CC)通常是gcc編譯器,但其它編譯器也是可以。 cc-option cc-option 用于檢測$(CC)是否支持給定的選項,如果不支持就使用第二個可選項。 例如: #arch/i386/Makefile cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586) 在上面例子中如果$(CC)支持-march=pentium-mmx則cflags-y等于該值,否則等于-march-i586。如果沒有第二個可選項且第一項不支持則cflags-y沒有被賦值。 cc-option-yn cc-option-yn用于檢測gcc是否支持給定的選項,支持返回‘y‘否則‘n‘。 例如: #arch/ppc/Makefile biarch := $(call cc-option-yn, -m32) aflags-$(biarch) += -a32 cflags-$(biarch) += -m32 在上面例子中如果$(CC)支持-m32選項則$(biarch)設(shè)置為y。當(dāng)$(biarch)等于y時,變量$(aflags-y)和$(cflags-y)將分別等于-a32和-m32。 cc-option-align gcc版本>= 3.0用于定義functions、loops等邊界對齊選項。 gcc < 3.00 cc-option-align = -malign gcc >= 3.00 cc-option-align = -falign 例如: CFLAGS += $(cc-option-align)-functions=4 在上面例子中對于gcc >= 3.00來說-falign-functions=4,gcc < 3.00版本使用-malign-functions=4。 cc-version cc-version返回$(CC)編譯器數(shù)字版本號。 版本格式是<major><minor>,均為兩位數(shù)字。例如gcc 3.41將返回0341。 當(dāng)一個特定$(CC)版本在某個方面有缺陷時cc-version是很有用的。例如-mregparm=3在一些gcc版本會失敗盡管gcc接受這個選項。 例如: #arch/i386/Makefile GCC_VERSION := $(call cc-version) cflags-y += $(shell \ if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;) 在上面例子中-mregparm=3只使用在版本大于等于3.0的gcc中。 === 7 Kbuild變量 頂層Makefile文件導(dǎo)出下面這些變量: VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION 這幾個變量定義了當(dāng)前內(nèi)核版本號。很少體系體系Makefiles文件直接使用他們,常用$(KERNELRELEASE)代替。 $(VERSION)、$(PATCHLEVEL)和$(SUBLEVEL)定義了三個基本部分版本號,例如"2", "4",和"0"。這三個變量一直使用數(shù)值表示。 $(EXTRAVERSION)定義了更細的補釘號,通常是短橫跟一些非數(shù)值字符串,例如"-pre4"。 KERNELRELEASE $(KERNELRELEASE)是一個單一字符如"2.4.0-pre4",適合用于構(gòu)造安裝目錄和顯示版本字符串。一些體系文件使用它用于以上目的。 ARCH 這個變量定義了目標(biāo)系統(tǒng)體系結(jié)構(gòu),例如"i386"、“arm"、"sparc". 一些內(nèi)核編譯文件測試$(ARCH)用于確定編譯哪個文件。默認(rèn)情況下頂層Makefile文件設(shè)置$(ARCH)為主機相同的系統(tǒng)體系。當(dāng)交叉編譯編譯 時,用戶可以使用命令行改變$(ARCH)值: make ARCH=m68k ... INSTALL_PATH 這個變量定義了體系Makefiles文件安裝內(nèi)核映項和System.map文件的路徑。 INSTALL_MOD_PATH, MODLIB $(INSTALL_MOD_PATH)定義了模塊安裝變量$(MODLIB)的前綴。這個變量通常不在Makefile文件中定義,如果需要可以由用戶添加。 $(MODLIB)定義了模塊安裝目錄。 頂層Makefile定義$(MODLIB)為$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)。用戶可以使用命令行修改這個值。 === 8 Makefile語言 內(nèi)核Makefiles設(shè)計目標(biāo)用于運行GNU Make程序。Makefiles僅使用GNU Make提到的特性,但使用了較多的GNU擴展部分。 GNU Make程序支持基本的列表處理功能。內(nèi)核Makefiles文件結(jié)合"if"語句使用了簡單的列表建立和維護功能。 GNU Make程序有兩種賦值操作符:":="和"="。 ":="執(zhí)行時立即計算右值并賦值給左值。"="類似公式定義,當(dāng)每次使用左值要被使用時計算右值并賦給它。 一些情況中使用"="合適,而一些情況中使用":="才是正確選擇。 === 9 Credits Original version made by Michael Elizabeth Chastain, <mailto:mec@shout.net> Updates by Kai Germaschewski < kai@tp1.ruhr-uni-bochum.de > Updates by Sam Ravnborg < sam@ravnborg.org > === 10 TODO - Describe how kbuild support shipped files with _shipped. - Generating offset header files. - Add more variables to section 7? |
|