linux kernel 的makefile的組織結構(轉)

linux kernel 的makefile的組織結構(轉)
 
 
背景知識:
背景知識一:Kconfig介紹:
在#make menuconfig 時,所顯示的Menu list是由各層Kconfig組成的。
最底層Kconfig存放在 ~/arch/i386/Kconfig. 以此爲頭,它會一層層使用source來把需要加入的各個目錄中Keconfig添加近來。
例如:source "drivers/Kconfig"
則將~/drivers/Kconfig添加進Menu list中。

背景知識二:Kconfig寫法語義:
config HID
tristate "Generic HID support"
depends on INPUT
default y
解釋如下:
config HID :表示此條目與CONFIG-HID對應。CONFIG-HID會在Makefile中用到。

tristate "Generic HID support" 引號內的內容是會顯示到Menu list中的。tristate表示這一項是三態的。

depends on INPUT:依賴於INPUT這一項。如果沒有選中INPUT,則Menu list不會顯示這項。

default y :缺省被選中。



背景知識三:built-in.o
vmlinux是Linux源碼編譯後未壓縮的內核, vmlinux是由arch/i386/kernel/head.o和arch/i386/kernel/init_task.o以及各個相關子目錄下的built-in.o鏈接而成的。


背景知識四:Kernel Makefile
Kernel中Makefile的體系以及如何編譯的,其實Sam一直是一知半解的。
其中,kernel目錄中的Makefile被稱爲底層Makefile。
當使用類似#make menuconfig配置內核成功後,會生成 .config文件。
換句話說:make menuconfig 時,Makefile會從~/arch/i386/Kconfig讀取Kconfig.然後根據用戶的選擇。生成.config文件。
例如:在drivers/hid/Kconfig:
config HID
tristate "Generic HID support"
如果用戶選中Y,則在.config中會反映出來:
CONFIG_HID=y
則在~/drivers/Makefile中可以看到:
obj-$(CONFIG_HID) += hid/
表明:如果CONFIG_HID是Y,則把hid目錄添加到要編譯的目錄中了。
進入到/driver/hid目錄,則看到:
hid-objs := hid-core.o hid-input.o
表明這兩個.o文件是一定會被編譯出的。
obj-$(CONFIG_HID) += hid.o
表明:如果CONFIG_HID是Y,則hid.o會被編譯出來。並built-in.
如果是 =m. 則hid.o被編譯出來,但最後被做成modules(ko)
 
背景知識五:KBuild Make:
Linux內核的Makefile與我們平時寫的Makefile有所不同,它由五部分組成:
1.Makefile : 頂層Makefile。
2. .config: kernel配置文件。
3. arch/xxx/Makefile: 具體架構的Makefile。
4. scripts/Makefile.xxx : 通用規則。
5. kbuild Makefile: 整個kernel中大約有數百個這種文件。

#make menuconfig後,生成 kernel配置文件: .config。
頂層Makefile讀取.config.
頂層Makefile通過解析 .config來決定遞歸訪問哪些目錄中的Kbuild Makefile .
這個過程中,Kbuild Makefile會按.config的設置,逐個添加文件列表,以供最後的編譯使用。
最簡單的KBuild Makefile如下:
obj-y += foo.o
表明:Kbuild在這目錄裏,有一個名爲foo.o的目標文件。foo.o將從foo.c或foo.S文件編譯得到。並且它會被包入built-in中去。
所 有編譯進內核的目標文件都存在$(obj-y)列表中。而這些列表依賴內核的配置。Kbuild編譯所有的$(obj-y)文件。然後,調用"$(LD) -r"將它們合併到一個build-in.o文件中。稍後,該build-in.o會被其父Makefile聯接進vmlinux中。

如果foo.o要編譯成一模塊,那就要用obj-m了。所採用的形式如下:
obj-m += foo.o



例一:
在 ~/driver/hid/hid-core.c中,有以下語句,即內核insmod接口hid_init.
module_init(hid_init);
也就是說,當此模塊被buildin或者作爲module insmod時,kernel會自動調用hid_init.
然後查看 ~/driver/hid/Makefile,發現
hid-objs := hid-core.o hid-input.o
表明只要hid這個目錄被加入,就會生成hid-core.o.
只好去看上一層目錄中怎樣會進入hid目錄:
obj-$(CONFIG_HID) += hid/
表明只要CONFIG_HID=Y,m. 則hid目錄被加入。
但用戶作了什麼,hid目錄被加入編譯呢?則看~/drivers/hid/Kconfig
config HID
tristate "Generic HID support"
以此得之只要在make menuconfig中選中此項,則hid-core.o被編譯出來。


例2:
Sam想要研究USB Keyboard & Mouse driver. 在 make menuconfig時,需要選中:
config USB_HID
tristate "USB Human Interface Device (full HID) support"
則查看Makefile。發現只要選中CONFIG_USB_HID.則會編譯出usb_hid.o
但~/drivers/hid/usbhid目錄中卻沒有usbhid.c。那usbhid.o如何生成的呢?
drivers/hid/usbhid目錄中,有個.usbhid.o.cmd文件。
 
_______________________________________________________________________________________________
 
 
linux kernel makefile
描述linux kernel 的makefile的組織結構,什麼是linux kernel 和 makefile 不用說了。

1. 概述

kernel的makefile分爲5個部分:

Makefile 最外面的Makefile
.config kernel的配置文件
arch/$(ARCH)/Makefile 不同架構cpu的makefile

scripts/Makefile.* 規則文件

kbuild Makefiles 500多個makefile文件

來看看kbuild makefile文件的構造規則定義。kbuild文件是組織kernel選項的文件。你會看到kbuild 和makefile 在一般同時存在一個目錄裏的。

目標定義:

一般都會用到此定義,此行的目的是要編譯成foo.o 文件,而源文件是默認的foo.c或者是foo.s 。源文件在kbuild文件的同級目錄裏。

obj-y += foo.o

如果要將此編譯成一個模塊,則需要用ojb-m 。如果想通過kernel的配置傳遞此參數,則需要寫下面的。

obj-$(CONFIG_FOO) += foo.o

(CONFIG_FOO) 就是你在kernel選項裏配置的,如果你沒有選中是built-in 還是 module,則此變量是y 或者 m的其他值,則不會編譯此文件。


built-in 目標文件:

當你obj-y 的時候,他們將會把所有的obj-y files 都編譯進去一個大的 built-in.o 目標文件。此後,會根據最上層的Makefile 鏈接成一個kernel p_w_picpath。


#drivers/isdn/i4l/Makefile # Makefile for the kernel ISDN subsystem and device drivers. # Each configuration option enables a list of files. obj-$(CONFIG_ISDN) += isdn.o obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
需要注意的是,您需要注意這些 目標文件的順序。
因爲一些函數例如(module_init() / __initcall) 是按照他們出現的順序被調用的。

ojb-m 目標:

這個是指要編譯成模塊。一個模塊可以由一個源文件或者多個組成。
linux/2.6.20.6/make menuconfig


當在頂層目錄執行”make menuconfig”會執行頂層Makefile 第415行的規則

config %config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@

這裏”menuconfig”與模式”%config”匹配。所以其執行的規則如下:

menuconfig: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig menuconfig

這個規則有三個依賴:scripts_basic、outputmakefile、FORCE。下面看一下這三個依賴:

1、 FORCE

首先分析一下這個依賴,它的規則定式義在1485行:

PHONY += FORCE
FORCE:

這個規則沒有命令也沒有依賴,它的目標也不是一個存在的文件名。在執行此規則時,目標FORCE總會被認爲是最新的。這樣當它作爲其它規則的依賴時,因爲依賴總被認爲被更新過的,所以那個規則的中定義的命令總會被執行。

2、 scripts_basic

這個依賴的規則在347行定義:

scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic

build這個變量定義在scripts/kbuild.include的114行:

build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj

所以上面的規則可寫成如下形式:

scripts_basic:
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj=scripts/basic

這個規則的命令最終會進入scripts目錄,執行Makefile.build文件,並傳遞參數obj=scripts/basic.

在Makefile.build的第5行有:

src := $(obj)

這就把傳遞進來的值賦給了src,所以

src := scripts/basic

從第16行開始的兩行把src (即scripts/basic)目錄下的Makefile包含進來(如果有Kbuild則包含Kbuild)

kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)

在第19行包含了scripts/Makefile.lib進來,

在Makefile.build的第83行,是make在Makefile.build中遇到的第一個目標

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m)) \
$(subdir-ym) $(always)
@:

KBUILD_BUILTIN在頂層Makefile的第207行定義

KBUILD_BUILTIN := 1

如果執行”make modules”,會在214行開始對其進行一些處理

ifeq ($(MAKECMDGOALS),modules)
KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
endif

所以我們這裏 KBUILD_BUILTIN :=1

KBUILD_MODULES在頂層Makefile的第206行定義,

KBUILD_MODULES :=

如果執行”make all”、”make _all”、”make modules”、”make”中任一個命令,則在222行開始會對這個變量進行處理

ifneq ($(filter all _all modules,$(MAKECMDGOALS)),)
KBUILD_MODULES := 1
endif

ifeq ($(MAKECMDGOALS),)
KBUILD_MODULES := 1
endif

因此,我們這裏KBUILD_MODULES :=

分析了這兩個變量後,上面的規則可重新寫爲

__build: $(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)
@:

這就是通過規則

scripts_basic:
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj=scripts/basic

在scripts/Makefile.build文件中執行的第一個規則,

規 則中的依賴由幾個變量$(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)表示。規則的命令是一個冒號命令”:”,冒號(:)命令是bash的內建命令,通常把它看作true命令。bash的help解釋 (help :)爲:No effect; the command does nothing. A zero exit code is returned.(沒有效果,該命令是空操作,退出狀態總是0)。
__build: $(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)
@:

構建一些依賴目標,這裏主要是構建$(always)變量指定的目標。其他變量在scripts/basic/Makefile中並沒有定義。

3、 outputmakefile

回到頂層Makefile中看規則

menuconfig: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig menuconfig

中的outputmakefile參數構建規則在357行開始定義

outputmakefile:
ifneq ($(KBUILD_SRC),)
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif

這個規則的命令運行一個shell腳本scripts/mkmakefile,並傳遞四個參數。這個腳本主要是在$(objtree)參數指定的目錄中生成一個Makefile文件。由於這裏KBUILD_SRC爲空,所以這個腳本並不會被執行

回頭再看看剛纔那個規則

menuconfig: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig menuconfig

在他的依賴被處理完後,開始執行規則的命令。第一個命令創建了兩個目錄,第二個命令擴展後爲

$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj =scripts/kconfig menuconfig

這 個命令依然是執行scripts/Makefile.build這個makefile文件。並執行它裏面menuconfig的規則。根據上面的分析,在 Makefile.build會包含scripts/kconfig/Makefile文件。然後執行以menuconfig爲目標的規則,在 scripts/kconfig/Makefile的13行定義

menuconfig: $(obj)/mconf
$< arch/$(ARCH)/Kconfig

從這個命令可以看出,最終會運行arch/arm/Kconfig這個腳本,出現配置界面

 

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