Linux Kernel Makefile

1、概述Makefile 由五個部分組成:Makefile:頂層 Makefile。 .config:內核配置文件。 arch/*/Makefile:體系結構 Makefiles。 子目錄 Makefile:大約三百個。 Rules.make:為所有子目錄 Makefile 提供通用規則。頂層 Makefile 讀入在內核配置過程中生成的 .config 文件。 頂層 Makefile 負責兩個主要產品的創建:vminux (常駐內核映象) 和模塊 (任何模塊文件)。它通過遞歸下降到內核源代碼樹以創建這些目標。需要進入的子目錄由內核配置確定。 頂層 Makefile 引入一個名為 arch/$(ARCH)/Makefile 的體系結構 Makefile。體系結構 Makefile 為頂層 Makefile 提供體系結構特定的信息。 每一子目錄都有一個 Makefile 以完成從上層傳遞來的命令。子目錄 Makefile 使用來自 .config 文件的信息以構造各種文件列表,而後引入 Rules.make 中的通用規則。 Rules.make 定義了所有子目錄 Makefile 的通用規則。它的一個變數列表組成了它的公共界面。而後它根據這些列表聲明規則。 2、誰需要什麼人們跟內核的 Makefile 有四種不同的關係。 用戶是創建內核的人。這些人輸入諸如「make menuconfig」或 「make bzImage」之類的命令。他們通常並不閱讀或編輯內核 Makefile (或任何其它源代碼)。 普通開發者是開發諸如設備驅動程序、文件系統或網路協議的人。這些人需要為他們開發的子系統維護用於該子系統的子目錄Makefile。為了有效地完成這一維護任務,他們需要一些關於內核 Makefile 的全局性的知識,以及一些關於 Rules.make公共界面的細節。 體系結構開發者是開發整個體系結構 (例如 spare 或 ia64) 的人。體系結構開發者需要理解體系結構 Makefile 以及子目錄 Makefile。 Kbuild 開發者是開發內核創建系統本身的人。這些人需要知道內核 Makefile 的所有方面。 本文檔是面向普通開發者和體系結構開發者的。 3、Makefile 語言內核 Makefile 被設計為使用 GNU Make。這些 Makefiles 只使用 GNU Make 文檔說明瞭的功能,但它們使用了很多 GNU 擴展。 GNU Make 支持基本列表處理函數。內核 Makefile 使用帶有少量 if 語句的新穎的列表創建和操作風格。 GNU Make 有兩種賦值操作符:「:=」和「=「。 ":= 」立即對右側進行求值並且將結果字元串存儲於左側變數中。「=」更像公式定義;它以未求值形式保存右側的內容並在使用左側變數的時候對此內容進行求值。 本文檔的所有示例都來自於實際的內核源代碼。這些示例都被重新排版過 (改變了空白符和行的劃分),但其它都完全一致。 4、從頂層傳遞下去的變數頂層 Makefile 導出以下變數: VERSION、 PATCHLEVEL、SUBLEVEL、EXTRAVERSION 這些變數定義了當前內核版本。少數體系結構 Makefile 直接使用這些值;它們應該使用 $(KERNELRELEASE)。$(VERSION)、$(PATCHLEVEL) 和 $(SUBLEVEL) 定義了三個基本版本編號,例如「2」、「4」和「0」。這三個值總是數值。$(EXTRAVERSION) 定義了更低級別的預備補丁或附加補丁。它通常是類似於 「-pre4的」非數值字元串,並且往往為空。 KERNELRELEASE $(KERNELRELEASE) 是類似於「2.4.0-pre4」的單個字元串,適於構造安裝目錄名或在版本字元串中顯示。某些體系結構 Makefile 將它用於這樣的目的。 ARCH 該變數定義了目標體系結構,例如「i386」、「arm」或 「sparc」。許多子目錄 Makefile 測試 $(ARCH) 以決定編譯那些文件。在默認情況下,頂層 Makefile 將 $(ARCH) 設定為主機系統的體系機構。為了進行交叉創建,用戶可以在命令行覆蓋 $(ARCH) 的值。make ARCH=m68k ... TOPDIR、HPATH $(TOPDIR) 是內核源代碼樹頂層目錄的路徑。子目錄 Makefile 需要此變數以便引入 $(TOPDIR)/Rules.make。$(HPATH) 等價於 $(TOPDIR)/include。少數體系結構 Makefile 需要它以使用引入文件做一些特殊的事。 SUBDIRS $(SUBDIRS) 是頂層 Makefile 應該進入以便完成 vmlinux 或模塊創建的目錄列表。$(SUBDIRS) 含有那些目錄取決於內核配置。頂層 Makefile 定義此變數,體系結構Makefile 擴展此變數。 HEAD、CORE_FILES、NETWORKS、DRIVERS、LIBS、LINKFLAGS $(HEAD)、$(CORE_FILES)、$(NETWORKS)、$(DRIVERS) 和 $(LIBS) 給出要連接到 vmlinux 中的目標文件和庫的列表。$(HEAD) 中的文件首先連接到 vmlinux 中。$(LINKFLAGS) 指定創建 vmlinux 的標誌。頂層 Makefile 和體系結構 Makefile 聯合定義這些變數。頂層 Makefile 定義$(CORE_FILES)、$(NETWORKS)、$(DRIVERS) 和 $(LIBS)。體系結構 Makefile 定義 $(HEAD)和 $(LINKFLAGS) 並擴展 $(CORE_FILES) 和 $(LIBS)。注意:這些變數並不都是必需的。$(NETWORKS)、$(DRIVERS)甚至 $(LIBS) 都應該合併到 $(CORE_FILES) 中去。 CPP、CC、AS、LD、AR、NM、STRIP、OBJCOPY、OBJDUMP、CPPFLAGS、CFLAGS、CFLAGS_KERNEL、MODFLAGS、AFLAGS、LDFLAGS、PERL、GENKSYMS 這些變數指定了 Rules.make 用於從源代碼文件創建目標文件的命令和標誌。$(CFLAGS_KERNEL) 含有用於編譯常駐內核代碼的附加 C 編譯器標誌。$(MODFLAGS) 含有用於編譯可載入內核模塊的附加 C 編譯器標誌。將來該標誌可能要改為更通用的 $(CFLAGS_MODULE)。$(AFLAGS) 含有彙編標誌。$(GENKSYMS) 含有用於生成在啟用了 CONFIG_MODVERSIONS 時內核符號簽名的命令。 genksyms 命令由 modutils 包提供。 CROSS_COMPILE 該變數是諸如 $(CC)、$(AS) 和 $(LD) 之類的其它變數的前綴路徑。體系結構Makefile 有時顯式使用並設置該變數。子目錄 Makefile 不需要關心它。如果需要,用戶可以在命令行中覆蓋 $(CROSS_COMPILE) 的值。 HOSTCC、HOSTCFLAGS 這些變數定義了用於編譯在本地主機運行的程序的 C 編譯器和 C 編譯器標誌。它們使用單獨的變數是因為目標體系結構可能於主機體系結構不同。 如果您的 Makefile 編譯並運行一個在創建內核的過程中運行的程序,那它就應該使用 $(HOSTCC) 和 $(HOSTCFLAGS)。 例如,drivers/pci 子目錄含有名為 gen-devlist.c 的助手程序。該程序讀入一個 PCI ID 列表並生成名為 classlist.h 和 devlist.h 的 C 代碼。 假定用戶有一臺 i386 計算機並需要創建一個用於 ia64 機器的內核。那麼用戶就應該在大多數編譯中使用 ia64 交叉編譯器,但應該使用 i386 本地編譯器編譯 drivers/pci/gen-devlist.c。 還有,諸如 scripts/mkdep.c 和 scripts/lxdialog/*.c 那樣的 kbuild 助手程序應該用 $(HOSTCC) 而不是 $(CC) 編譯。 ROOT_DEV、SVGA_MODE、RAMDISK 最終用戶編輯該變數以指定關於他們的內核的特定配置信息。這些變數是古董!他們也只能用於 i386 體系結構。他們實在是應該用 CONFIG_* 選項來替代了。 MAKEBOOT 該變數只在頂層 Makefile 中定義和使用。頂層 Makefile 不該導出它。 INSTALL_PATH 該變數定義了體系結構 Makefile 應該將常駐內核映象和 System.map 文件安裝到那裡去。 INSTALL_MOD_PATH、MODLIB $(INSTALL_MOD_PATH) 指定了用於安裝模塊的 $(MODLIB) 的前綴。 Makefile 沒有定義該變數,但如果需要的話,用戶可以定義它。 $(MODLIB) 指定了模塊安裝的目錄。頂層 Makefile 將 $(MODLIB) 定義為 $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)。如果需要用戶可以在命令行中覆蓋這個值。 CONFIG_SHELL 該變數是 Makefile 和 Rules.make 間私有的變數。體系結構 Makefile 和子目錄 Makefile 不應該使用它。 MODVERFILE 內部變數。由於它從不在頂層 Makefile 以外使用,所以不必導出它。 MAKE、MAKEFILES 一些 GNU Make 的內部變數。 $(MAKEFILES) 特別用於強制體系結構 Makefile 和子目錄 Makefile 讀入 $(TOPDIR)/.config 而不必顯式地引入它。(這是個實線細節並可以修正)。 5、體系結構 Makefile 的結構5.1、體系結構特定的變數頂層 Makefile 引入一個體系結構 Makefile:arch/$(ARCH)/Makefile。本節解說體系結構 Makefile 的功能。 體系結構 Makefile 用體系結構特定的至擴展了某些頂層 Makefile 的變數。 SUBDIRS 頂層 Makefile 定義 $(SUBDIRS)。體系結構 Makefile 用一組體系結構特定的目錄擴展 $(SUBDIRS)。 例如: # arch/alpha/Makefile SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm arch/alpha/lib arch/alpha/math-emu該列表可能依賴於配置: # arch/arm/Makefile ifeq ($(CONFIG_ARCH_ACORN),y) SUBDIRS += drivers/acorn ... endif CPP、CC、AS、LD、AR、NM、STRIP、OBJCOPY、OBJDUMP、CPPFLAGS、CFLAGS、CFLAGS_KERNEL、MODFLAGS、AFLAGS、LDFLAGS 頂層 Makefile 定義了這些變數,體系結構 Makefile 擴展了它們。 很多體系結構 Makefile 動態地運行目標 C 編譯器以探測它所支持的選項: # arch/i386/Makefile # prevent gcc from keeping the stack 16 byte aligned CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi)而且,$(CFLAGS) 當然可能依賴於配置: # arch/i386/Makefile ifdef CONFIG_M386 CFLAGS += -march=i386 endif ifdef CONFIG_M486 CFLAGS += -march=i486 endif ifdef CONFIG_M586 CFLAGS += -march=i586 endif某些體系結構 Makefile 重新定義了編譯命令以添加體系結構特定的標誌: # arch/s390/Makefile LD=$(CROSS_COMPILE)ld -m elf_s390 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S 5.2、vmlinux 創建變數體系結構 Makefile 和頂層 Makefile 合作以定義確定了如何創建 vmlinux 文件的變數。請注意沒有對應的體系結構特定的模塊部分;模塊創建機制跟體系結構是完全獨立的。 HEAD、CORE_FILES、LIBS、LINKFLAGS 頂層 Makefile 定義了這些變數於體系結構獨立的內容,而體系結構 Makefile 擴展了它們。請注意體系結構 Makefile 定義 (而不僅僅是擴展了) $(HEAD) 和 $(LINKFLAGS)。 例如: # arch/m68k/Makefile ifndef CONFIG_SUN3 LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds else LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N endif ... ifndef CONFIG_SUN3 HEAD := arch/m68k/kernel/head.o else HEAD := arch/m68k/kernel/sun3-head.o endif SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES) LIBS += arch/m68k/lib/lib.a 5.3、後-vmlinux 目標體系結構 Makefile 定義了獲取 vmlinux 文件、壓縮它、以啟動代碼包裝它、並將結果文件複製到某處的目標。這包括各種類型的安裝命令。 這些後-vmlinux 目標在不同體系結構之間並不通用。下面是這些目標和支持它們的體系結構的列表 (來自於內核版本 2.4.0-test6-pre5): balo mips bootimage alpha bootpfile alpha、ia64 bzImage i386、m68k bzdisk i386 bzlilo i386 compressed i386、m68k、mips、mips64、sh dasdfmt s390 Image arm image s390 install arm、i386 lilo m68k msb alpha、ia64 my-special-boot alpha、ia64 orionboot mips rawboot alpha silo s390 srmboot alpha tftpboot.img sparc、sparc64 vmlinux.64 mips64 vmlinux.aout sparc64 zImage arm, i386, m68k, mips, mips64, ppc, sh zImage.initrd ppc zdisk i386, mips, mips64, sh zinstall arm zlilo i386 znetboot.initrd ppc 5.4、強制性體系結構特定的目標體系結構 Makefile 必須定義以下體系結構特定的目標。這些目標為對應的頂層 Makefile 目標提供了體系結構特定的工作: archclean clean archdep dep archmrproper mrproper 6、子目錄 Makefile 的結構子目錄 Makefile 有四個部分。 6.1、注釋第一部分是注釋頭。歷史上很多匿名人士編輯了內核 Makefile 而沒有在頭中留下任何修改記錄;來自他們的注釋將是很有價值的。 6.2、目標定義第二部分是一組作為子目錄 Makefile 核心的定義。這些行定義了需要創建的文件、所有特殊的編譯選項,以及必須遞歸進入的子目錄。這些行的聲明嚴重地依賴於內核配置變數 (CONFIG_* 符號)。 第二部分看起來是這樣: # drivers/block/Makefile obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o6.3、Rules.make 部分第三部分只有一行: include $(TOPDIR)/Rules.make6.4、特殊規則第四部分含有任何必需而 Rules.make 中的通用規則無法完成的特殊的 Makefile 規則。 7、Rules.make 變數Rules.make 的公共界面由以下變數組成: 7.1、子目錄一個 Makefile 只負責它所在目錄目標文件的創建。子目錄中的文件應該由那些子目錄中的 Makefile 來創建。只要你讓創建系統知道這些子目錄,創建系統就會自動調用 make 以遞歸地進入子目錄。 為此,使用 subdir-{y,m,n,} 變數: subdir-$(CONFIG_ISDN) += i4l subdir-$(CONFIG_ISDN_CAPI) += capi在實際創建內核時,例如:vmlinux (「make {vmlinux、bzImage、...」),make 將遞歸下降到由 $(subdir-y) 列舉的目錄中。 當創建模塊時 (「make modules」),make 將遞歸下降到由 $(subdir-m) 列舉的目錄中。 當創建依賴性關係時(「make dep」),make 需要察看所有子目錄,所以它將下降到由 $(subdir-y)、$(subdir-m)、$(subdir-n)、$(subdir-) 列舉的所有子目錄。 您可能會遇到配置選項被設置為「y」,但您仍然需要在那個子目錄中創建模塊的情況。 例如,drivers/isdn/capi/Makefile 中有: obj-$(CONFIG_ISDN_CAPI) += kernelcapi.o capiutil.o obj-$(CONFIG_ISDN_CAPI_CAPI20) += capi.o可能 CONFIG_ISDN_CAPI=y,但 CONFIG_ISDN_CAPI_CAPI20=m。 這可以在其父母錄的 Makefile 以如下形式來表述: mod-subdirs := i4l hisax capi eicon subdir-$(CONFIG_ISDN_CAPI) += capi即使子目錄 (「capi」) 只出現在 $(subdir-y) 而不在 $(subdir-m) 中出現,使子目錄 (「capi」) 出現在 $(mod-subdirs) 變數中使創建系統在 「make modules」 的過程中進入該子目錄。 7.2、目標文件目標 O_TARGET, obj-y 子目錄 Makefile 在列表 $(obj-y) 中為 vmlinux 指定目標文件。這些列表依賴於內核配置。 Rules.make 編譯所有的 $(obj-y) 文件。而後它調用 「$(LD) -r」 以將這些文件合併成為一個名為 $(O_TARGET) 的 .o 文件。這個 $(O_TARGET) 將來由父 Makefile 連接到 vmlinux 之中。 $(obj-y) 中文件的順序是重要的。允許列表中出現重複:第一次出現將被連接到 $(O_TARGET),而忽略隨後的出現。 連接順序是重要的,這是因為某些函數在啟動時將按照它們出現的順序被調用。所以要記住改變連接順序,比如說,就可能改變您探測到 SCSI 控制器的順序,從而改變您磁碟的編號。 例如: # Makefile for the kernel ISDN subsystem and device drivers. # The target object and module list name. O_TARGET := vmlinux-obj.o # Each configuration option enables a list of files. obj-$(CONFIG_ISDN) += isdn.o obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o # The global Rules.make. include $(TOPDIR)/Rules.make 7.3、庫文件目標 L_TARGET 除了創建 O_TARGET 目標文件,您還可以再為 $(obj-y) 列舉的目標文件創建靜態連接庫。通常不必這樣做,它只用於 lib、arch/$(ARCH)/lib 目錄。 7.4、可載入模塊目標 obj-m $(obj-m) 指定了作為可載入內核模塊創建的目標文件。 一個模塊可以從一個或多個源代碼文件中創建出來。如果是一個源代碼文件,子目錄 Makefile 僅僅將文件添加到 $(obj-m) 即可。 例如: obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o如果內核模塊是從多個源代碼文件中創建出來,您就以跟上面相同的方法指定您要創建的模塊。 然而,創建系統當然需要知道您要創建的模塊的各個部分,所以您必須通過設定變數 $(<模塊名>-obj) 來告訴它。 例如: obj-$(CONFIG_ISDN) += isdn.o isdn-objs := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o在這個例子中,模塊名為 isdn.o。Rules.make 將編譯列舉在 $(isdn-objs) 中的文件,而後對這些文件運行「$(LD) -r」以生成 isdn.o。 注意:當然,當您將目標文件創建到內核之中時,以上語法仍然是有效的。所以,如果您的 CONFIG_ISDN=y,創建系統將按照您所預期的,由它的各個部分為您創建出 isdn.o,然後將它連接到 $(O_TARGET) 之中。 7.5、帶有導出符號的目標文件 export-objs 當使用可載入模塊時,不是所有內核/其它模塊中的全局符號 都自動成為可用的,您的模塊只能使用那些顯式導出的符號。 為了讓模塊能夠使用某個符號,要「導出」它,在源代碼中使用 EXPORT_SYMBOL()。此外,您還要在 Makefile 變數 $(export-objs) 中列舉所有導出符號的文件(例如,含有 EXPORT_SYMBOL() 指令的源代碼)。 例如: # Objects that export symbols. export-objs := isdn_common.o這是因為 isdn_common.c 含有 EXPORT_SYMBOL(register_isdn);這使得底層 ISDN 驅動程序能夠使用函數 register_isdn。 7.6、編譯標誌 EXTRA_CFLAGS、EXTRA_AFLAGS、EXTRA_LDFLAGS、EXTRA_ARFLAGS $(EXTRA_CFLAGS) 指定用 $(C) 編譯 C 文件的選項。該變數中的選項用於當前目錄中編譯所有文件用的 $(CC) 命令。 例如: # drivers/sound/emu10k1/Makefile EXTRA_CFLAGS += -I. ifdef DEBUG EXTRA_CFLAGS += -DEMU10K1_DEBUG endif當前目錄的子目錄並不使用 $(EXTRA_CFLAGS)。此外,它也不用於由 $(HOSTCC) 編譯的文件。 由於頂層 Makefile 擁有變數 $(CFLAGS) 並將該變數用於整個源代碼樹,因此 $(EXTRA_CFLAGS) 是必需的。 $(EXTRA_AFLAGS) 是用於編譯彙編語言源代碼的類似的單個目錄選項字元串。 示例:在編寫本文時,內核源代碼中尚無使用 $(EXTRA_AFLAGS) 的例子。 $(EXTRA_LDFLAGS) 和 $(EXTRA_ARFLAGS) 用於 $(LD) 和 $(AR) 的類似的單個目錄選項字元串。 示例:在編寫本文時,內核源代碼中尚無使用 $(EXTRA_LDFLAGS) 或 $(EXTRA_ARFLAGS) 的例子。 CFLAGS_$@, AFLAGS_$@ $(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) -traditionalRules.make有讓目標文件依賴於用於編譯它的 $(CFLAGS_$@) 的值的功能。因此,如果你為某個文件改變了 $(CFLAGS_$@) 的值,不論是編輯Makefile 還是以其他某種方式覆蓋了原來的值,Rules.make 都會正確地工作並以新選項重新編譯您的源代碼。 請注意:由於 Rules.make 的缺陷,彙編語言沒有標誌依賴性。如果您為某個文件編輯了 $(AFLAGS_$@),您就必須刪除目標文件以便從源文件重新創建它。 LD_RFLAG 使用但從未定義該變數。這似乎是某種已放棄的嘗試的遺跡。 7.7、其它變數 IGNORE_FLAGS_OBJS $(IGNORE_FLAGS_OBJS) 是一個無法自動跟蹤標誌依賴性關係的目標文件的列表。這是個補充功能,用於處理實現依賴性標誌中的問題。(問題是標誌依賴性假定 %.o 文件是從一個匹配的 %.S 或 %.c 中創建出來的。有時並不是這樣)。 USE_STANDARD_AS_RULE 這是一個過渡變數。如果定義了 $(USE_STANDARD_AS_RULE) , Rules.make 就為將 %.S 文件彙編為 %.o 文件或 %.s 文件 (%.s 文件只對開發者纔有用) 提供標準規則。 如果沒有定義 $(USE_STANDARD_AS_RULE),那麼 Rules.make 就不提供這些標準規則。在這種情況下,子目錄 Makefile 必須為彙編 %.S 文件提供它的私有規則。 在過去,所有 Makefile 都提供私有的 %.S 規則。較新的 Makefiles 應該定義 USE_STANDARD_AS_RULE並使用標準的 Rules.make 規則。一旦所有體系結構的所有 Makefile 都使用 USE_STANDARD_AS_RULE,那麼Rules.make 就可以取消對 USE_STANDARD_AS_RULE 的測試。此後,所有其它 Makefile 就可以取消對USE_STANDARD_AS_RULE 的定義。 8、新風格變數[ 本章回溯到將前面描述的編寫 Makefile 的方式稱為「新風格」的時候。由於換句話說它仍然表述了同樣的事,所以我在此保持了這種說法,這可能有些用處 ] 「新風格變數」比「舊風格變數」更簡單更有效。因此,許多子目錄 Makefile 可以縮減 60%。作者希望所有體系結構 Makefile 和子目錄 Makefile 都能及時轉換到新風格。 Rules.make 並不理解新風格變數。因此,每個新風格 Makefile 都有一個樣板代碼部分以便將新風格變數轉換為舊風格變數。這有點混淆,人們以「新風格」定義大部分變數但最後幾行又落入了「舊風格」。 8.1、新變數 obj-y obj-m obj-n obj- 這些變數代替了 $(O_OBJS)、$(OX_OBJS)、$(M_OBJS) 和 $(MX_OBJS)。 例如: # drivers/block/Makefile obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o請注意這裡用 $(CONFIG_...) 在賦值操作符左側進行替換。這使 GNU Make 具有組合索引的能力!每個這樣的賦值替換了舊風格 Makefile 中的八行代碼。 在執行所有的賦值之後,子目錄 Makefile 就創建了四個列表:$(obj-y)、$(obj-m)、 $(obj-n) 和 $(obj-)。 $(obj-y) 是包含在 vmlinux 之中的文件的列表。 $(obj-m) 是作為單獨模塊創建的文件列表。 忽略 $(obj-n) 和 $(obj-)。 每個列表都可能含有重複項目;此後重複的項目將被自動刪除。同時出現在 $(obj-y) 和 $(obj-m) 中的文件將自動從 $(obj-m) 列表中刪除。 Example: # drivers/net/Makefile ... obj-$(CONFIG_OAKNET) += oaknet.o 8390.o ... obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o ... obj-$(CONFIG_STNIC) += stnic.o 8390.o ... obj-$(CONFIG_MAC8390) += daynaport.o 8390.o ...在這個例子中,四個不同的驅動程序都需要 8390.o 中的代碼。如果這四個驅動程序中的一個或多個要創建到 vmlinux之中,即使其它驅動程序需要 8390.o 作為模塊進行創建,8390.o 就會被創建到 vmlinux之中而不是成為一個模塊。(模塊化的驅動程序能夠使用常駐於 vmlinux 映像中的 8390.o 代碼提供的服務)。 export-objs $(export-objs) 是子目錄中所有可能導出符號的文件的列表。構造該列表的規範方法是: grep -l EXPORT_SYMBOL *.c(但看看那些在引入頭文件中偷偷調用 EXPORT_SYMBOL 的文件吧!) 這是個可能的列表,與內核配置無關。$(export-objs) 列舉出所有導出符號的文件。而後樣板代碼就用 $(export-objs) 來將實際的文件列表劃分為 $(*_OBJS) 和 $(*X_OBJS)。 經驗表明在舊風格 Makefile 中維護一個正確的 X 變數有困難並容易出錯。在新風格 Makefile 中維護 $(export-objs) 比較簡單並便於核對。 $(foo)-objs 某些內核模塊由多個目標文件連接組成。 對於每個多部分內核模塊,都有一個列表列出所有組成該模塊的目標文件。對於名為 foo.o 的內核模塊,它的目標文件列表就是 foo-objs。 例如: # drivers/scsi/Makefile list-multi := scsi_mod.o sr_mod.o initio.o a100u2w.o ... scsi_mod-objs := hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o scsi_queue.o scsi_lib.o scsi_merge.o scsi_dma.o scsi_scan.o scsi_syms.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o initio-objs := ini9100u.o i91uscsi.o a100u2w-objs := inia100.o i60uscsi.o子目錄 Makefile 將以常見的配置相關方式將模塊加入 obj-* 列表: obj-$(CONFIG_SCSI) += scsi_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_SCSI_INITIO) += initio.o obj-$(CONFIG_SCSI_INIA100) += a100u2w.o假定 CONFIG_SCSI=y。那麼 vmlinux 就需要把它的 14 組件連接為 scsi_mod.o。 假定 CONFIG_BLK_DEV_SR=m。那麼 sr_mod.o 的三個組件就要以 「$(LD) -r」 連接到一起以組成內核模塊 sr_mod.o。 再假定 CONFIG_SCSI_INITIO=n。那麼 initio.o 就進入 $(obj-n) 列表而且這就是它的終點了。不會編譯它的組件文件,也不會創建組合文件。 subdir-y subdir-m subdir-n subdir- 這些變數替代了 $(ALL_SUB_DIRS)、$(SUB_DIRS) 和 $(MOD_SUB_DIRS)。 例如: # drivers/Makefile subdir-$(CONFIG_PCI) += pci subdir-$(CONFIG_PCMCIA) += pcmcia subdir-$(CONFIG_MTD) += mtd subdir-$(CONFIG_SBUS) += sbus這些變數按類似於 obj-* 的方式工作,但用於子目錄而不是目標文件。 在所有賦值完成後,子目錄 Makefile 就組成了四個列表:$(subdir-y)、$(subdir-m)、 $(subdir-n) 和 $(subdir-)。 $(subdir-y) 是創建 vmlinux 時應該進入的子目錄列表。 $(subdir-m) 是創建模塊時應該進入的子目錄列表。 $(subdir-n) 和 $(subdir-) 只用於收集本目錄的所有子目錄的列表。 除 subdir-y 以外每個列表都可能含有重複項目;此後將自動刪除重複項目。 mod-subdirs $(mod-subdirs) 是一個所有即使出現在 $(subdir-y) 中也應該加入 $(subdir-m) 的子目錄的列表。 例如: # fs/Makefile mod-subdirs := nls這意味著如果 CONFIG_NLS=y,nls 應該加入 $(subdir-y) 和 $(subdir-m)。


推薦閱讀:
查看原文 >>
相關文章