linux 内核 企鹅,Linux 内核 Makefile 体系简单分析
眾所周知,Linux內(nèi)核是使用make命令來配置并編譯的,那必然少不了Makefile。在內(nèi)核目錄樹中我們可以看到內(nèi)核編譯系統(tǒng)的頂層Makefile文件。但是如此復(fù)雜、龐大的內(nèi)核源碼絕不可能使用一個或幾個Makefile文件來完成配置編譯,而是需要一套同樣復(fù)雜、龐大,且為Linux內(nèi)核定制的Makefile系統(tǒng)。她可以說是內(nèi)核的一個子系統(tǒng),是內(nèi)核中比較特殊的一部分,幾乎都是應(yīng)用層的程序和腳本,但又和生成的內(nèi)核二進(jìn)制文件息息相關(guān)。編譯不僅涉及本地編譯,還涉及各個平臺之間的交叉編譯以及二進(jìn)制文件格式處理等等。她是對Makefile在功能上的擴(kuò)充,使其在配置編譯Linux內(nèi)核的時候更加靈活、高效和簡潔。
盡管她是一個復(fù)雜的系統(tǒng),但對絕大部分內(nèi)核開發(fā)者來說只需要知道如何使用,而無需了解其中的細(xì)節(jié)。她對絕大部分內(nèi)核開發(fā)者基本上是透明的,隱藏了大部分實現(xiàn)細(xì)節(jié),有效地降低了開發(fā)者的負(fù)擔(dān),能使其能專注于內(nèi)核開發(fā),而不至于花費時間和精力在編譯過程上。
以下我們就來簡要的了解一下內(nèi)核Makefile體系。
一、內(nèi)核Makefile體系概述
其實內(nèi)核Makefile體系的包含了Kconfig和Kbuild兩個系統(tǒng)。她曾經(jīng)的維護(hù)人是Sam
Ravnborg <>,現(xiàn)在的暫時沒有查到。參考資料:
Kconfig對應(yīng)的是內(nèi)核配置階段,如你使用命令:make menuconfig,就是在使用Kconfig系統(tǒng)。Kconfig由以下三部分組成:
scripts/kconfig/*
Kconfig文件解析程序
kconfig
各個內(nèi)核源代碼目錄中的kconfig文件
arch/$(ARCH)/configs/*_defconfig
各個平臺的缺省配置文件
當(dāng)Kconfig系統(tǒng)生成.config后,Kbuild會依據(jù).config編譯指定的目標(biāo)。后面我會簡單地對make %config的流程進(jìn)行情景分析,這里不必贅述。
Kbuild是內(nèi)核Makefile體系重點,對應(yīng)內(nèi)核編譯階段,由5個部分組成:
頂層Makefile
根據(jù)不同的平臺,對各類target分類并調(diào)用相應(yīng)的規(guī)則Makefile生成目標(biāo)
.config
內(nèi)核配置文件
arch/$(ARCH)/Makefile
具體平臺相關(guān)的Makefile
scripts/Makefile.*
通用規(guī)則文件,面向所有的Kbuild Makefiles,所起的作用可以從后綴名中得知。
各子目錄下的Makefile文件
由其上層目錄的Makefile調(diào)用,執(zhí)行其上層傳遞下來的命令
而其中scripts目錄下的編譯規(guī)則文件和其目錄下的C程序在整個編譯過程起著重要的作用。列舉如下:
文件名
作用
Kbuild.include
共用的定義文件,被許多獨立的Makefile.*規(guī)則文件和頂層Makefile包含
Makefile.build
提供編譯built-in.o, lib.a等的規(guī)則
Makefile.lib
負(fù)責(zé)歸類分析obj-y、obj-m和其中的目錄subdir-ym所使用的規(guī)則
Makefile.host
本機(jī)編譯工具(hostprog-y)的編譯規(guī)則
Makefile.clean
內(nèi)核源碼目錄清理規(guī)則
Makefile.headerinst
內(nèi)核頭文件安裝時使用的規(guī)則
Makefile.modinst
內(nèi)核模塊安裝規(guī)則
Makefile.modpost
模塊編譯的第二階段,由.o和.mod生成.ko時使用的規(guī)則
頂層Makefile主要是負(fù)責(zé)完成vmlinux(內(nèi)核文件)與*.ko(內(nèi)核模塊文件)的編譯。頂層Makefile讀取.config文件,并根據(jù).config文件確定訪問哪些子目錄,并通過遞歸向下訪問子目錄的形式完成。頂層Makefile同時根據(jù).config文件原封不動的包含一個具體架構(gòu)的Makefile,其名字類似于arch/$(ARCH)/Makefile。該架構(gòu)Makefile向頂層Makefile提供其架構(gòu)的特別信息。
每一個子目錄都有一個Makefile文件,用來執(zhí)行從其上層目錄傳遞下來的命令。子目錄的Makefile也從.config文件中提取信息,生成內(nèi)核編譯所需的文件列表。
二、內(nèi)核Makefile導(dǎo)讀與情景分析
1、概述
上面簡要介紹了內(nèi)核Makefile的總體結(jié)構(gòu),但當(dāng)我們打開頂層Makefile文件時還是因為她的復(fù)雜而覺得無從下手。但是內(nèi)核Makefile就是Makefile,和最簡單的Makefile遵循著同樣的規(guī)則。所以只要我們靜下心來分析,還是可以理解的。當(dāng)然,在閱讀內(nèi)核的Makefile前,你必須對Makefile和shell腳本有一定的基礎(chǔ)。
推薦參考資料:
《》?翻譯整理:徐海兵??PDF文檔
《》翻譯:楊春敏 黃毅
根據(jù)Makefile的執(zhí)行規(guī)則,在分析Makefile時,首先必須確定一個目標(biāo),然后才能確定所有的依賴關(guān)系,最后根據(jù)更新情況決定是否執(zhí)行相應(yīng)的命令。所以要看懂內(nèi)核Makefile的大致框架,我們首先要了解她里面所定義的目標(biāo)。而內(nèi)核Makefile所定義的目標(biāo)基本上可以通過make help打印出來(因為help本身就是頂層Makefile的一個目標(biāo),里面是打印幫助信息的“echo”命令)。
這些目標(biāo)可以分為以下幾個大類:
目標(biāo)
常用目標(biāo)舉例
作用
配置
%config
config
啟動Kconfig,以不同界面來配置內(nèi)核。
menuconfig
xconfig
編譯
all
編譯vmlinux內(nèi)核映像和內(nèi)核模塊
vmlinux
編譯vmlinux內(nèi)核映像
modules
編譯內(nèi)核模塊
安裝
headers_install
安裝內(nèi)核頭文件/模塊
modules_install
源碼瀏覽
tags
生成代碼瀏覽工具所需要的文件
TAGS
cscope
靜態(tài)分析
checkstack
檢查并分析內(nèi)核代碼
namespacecheck
headers_check
內(nèi)核打包
%pkg
以不同的安裝格式編譯內(nèi)核
文檔轉(zhuǎn)換
%doc
把kernel文檔轉(zhuǎn)成不同格式
構(gòu)架相關(guān)
(以arm為例)
zImage
生成壓縮的內(nèi)核映像
uImage
生成壓縮的u-boot可引導(dǎo)的內(nèi)核映像
install
安裝內(nèi)核映像
其中的構(gòu)架相關(guān)目標(biāo)在頂層Makefile上并未出現(xiàn),而是被包含在平臺相關(guān)的Makefile(arch/$(ARCH)/Makefile)中。
2、情景分析
以下我們就來分析一個簡單的目標(biāo)(menuconfig),作為情景分析范例來演示一下內(nèi)核Makefile的分析方法。
首先當(dāng)我們在內(nèi)核源碼的根目錄下執(zhí)行make menuconfig命令時,根據(jù)規(guī)則,make程序讀取頂層Makefile文件及其包含的Makefile文件,內(nèi)建所有的變量、明確規(guī)則和隱含規(guī)則,并建立所有目標(biāo)和依賴之間的依賴關(guān)系結(jié)構(gòu)鏈表。make程序最終會調(diào)用規(guī)則:
config %config: scripts_basic
outputmakefile FORCE
$(Q)mkdir
-p include/linux include/config
$(Q)$(MAKE)
$(build)=scripts/kconfig $@
調(diào)用的原因是我們指定的目標(biāo)“menuconfig”匹配了“%config”。
她的依賴目標(biāo)是scripts_basic和outputmakefile,以及FORCE。也就是說在完成了這3個依賴目標(biāo)后,下面的兩個命令才會執(zhí)行以完成我們指定的目標(biāo)“menuconfig”。
所以我們來看看這三個依賴目標(biāo)實現(xiàn)的簡要過程:
(1)scripts_basic
make程序會調(diào)用規(guī)則:
scripts_basic:
$(Q)$(MAKE)
$(build)=scripts/basic
他沒有依賴目標(biāo),所以直接執(zhí)行了以下的指令,只要將指令展開,我們就知道m(xù)ake做了什么操作。其中比較不好展開的是$(build),她的定義在scripts/Kbuild.include中:
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build
obj
所以展開后是:
make -f scripts/Makefile.build obj= scripts/basic
也就是make解析執(zhí)行scripts/Makefile.build文件,且參數(shù)obj=
scripts/basic。而在解析執(zhí)行scripts/Makefile.build文件的時候,scripts/Makefile.build又會通過解析傳入?yún)?shù)來包含對應(yīng)文件夾下的Makefile文件(scripts/basic/Makefile),從中獲得需要編譯的目標(biāo)。
在確定這個目標(biāo)以后,通過目標(biāo)的類別來繼續(xù)包含一些scripts/Makefile.*文件。例如scripts/basic/Makefile中內(nèi)容如下:
hostprogs-y := fixdep docproc hash
always????? := $(hostprogs-y)
# fixdep is needed to
compile other host programs
$(addprefix
$(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
所以scripts/Makefile.build會包含scripts/Makefile.host。相應(yīng)的語句如下:
# Do not include host
rules unless needed
ifneq
($(hostprogs-y)$(hostprogs-m),)
include
scripts/Makefile.host
endif
此外scripts/Makefile.build會包含include
scripts/Makefile.lib等必須的規(guī)則定義文件,在這些文件的共同作用下完成對scripts/basic/Makefile中指定的程序編譯。
由于Makefile.build的解析執(zhí)行牽涉了多個Makefile.*文件,過程較為復(fù)雜,礙于篇幅無法一條一條指令的分析,興趣的讀者可以自行分析。
推薦兩篇經(jīng)典的分析文檔:
《Kbuild系統(tǒng)原理分析》 ?作者未知,網(wǎng)上有PDF文檔
(2)outputmakefile
make程序會調(diào)用規(guī)則:
PHONY += outputmakefile
# outputmakefile
generates a Makefile in the output directory, if using a
# separate output
directory. This allows convenient use of make in the
# output directory.
outputmakefile:
ifneq ($(KBUILD_SRC),)
$(Q)ln -fsn $(srctree) source
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
$(srctree) $(objtree)
$(VERSION) $(PATCHLEVEL)
endif
從這里我們可以看出:outputmakefile是當(dāng)KBUILD_SRC不為空(指定O=dir,編譯輸出目錄和源代碼目錄分開)時,在輸出目錄建立Makefile時才執(zhí)行命令的,
如果我們在源碼根目錄下執(zhí)行make menuconfig命令時,這個目標(biāo)是空的,什么都不做。
如果我們指定了O=dir時,就會執(zhí)行源碼目錄下的scripts/mkmakefile,用于在指定的目錄下產(chǎn)生一個Makefile,并可以在指定的目錄下開始編譯。
(3)FORCE
這是一個在內(nèi)核Makefile中隨處可見的偽目標(biāo),她的定義在頂層Makefile的最后:
PHONY
+= FORCE
FORCE:
是個完全的空目標(biāo),但是為什么要定義一個這樣的空目標(biāo),并讓許多目標(biāo)將其作為依賴目標(biāo)呢?原因如下:
正因為FORCE是一個沒有命令或者依賴目標(biāo),不可能生成相應(yīng)文件的偽目標(biāo)。當(dāng)make執(zhí)行此規(guī)則時,總會認(rèn)為FORCE不存在,必須完成這個目標(biāo),所以她是一個強(qiáng)制目標(biāo)。也就是說:規(guī)則一旦被執(zhí)行,make就認(rèn)為它的目標(biāo)已經(jīng)被執(zhí)行并更新過了。當(dāng)她作為一個規(guī)則的依賴時,由于依賴總被認(rèn)為被更新過的,因此作為依賴所在的規(guī)則中定義的命令總會被執(zhí)行。所以可以這么說:只要執(zhí)行依賴包含F(xiàn)ORCE的目標(biāo),其目標(biāo)下的命令必被執(zhí)行。
在make完成了以上3個目標(biāo)之后,就開始執(zhí)行下面的命令的,首先是
$(Q)mkdir -p
include/linux include/config
這個很好理解,就是建立兩個必須的文件夾。然后
$(Q)$(MAKE)
$(build)=scripts/kconfig $@
這和我們上面分析的$(Q)$(MAKE)
$(build)=結(jié)構(gòu)相同,將其展開得到:
make -f
scripts/Makefile.build obj=scripts/kconfigmenuconfig
所以這個指令的效果是使make解析執(zhí)行scripts/Makefile.build文件,且參數(shù)obj=scripts/kconfig
menuconfig。這樣Makefile.build會包含對應(yīng)文件夾下的Makefile文件(scripts/kconfig /Makefile),并完成scripts/kconfig /Makefile下的目標(biāo):
menuconfig:
$(obj)/mconf
$< $(Kconfig)
這個目標(biāo)的依賴條件是$(obj)/mconf,通過分析可知她其實是對應(yīng)以下規(guī)則:
mconf-objs? := mconf.o zconf.tab.o $(lxdialog)
……
ifeq
($(MAKECMDGOALS),menuconfig)
hostprogs-y += mconf
endif
也就是編譯生成本機(jī)使用的mconf程序。完成依賴目標(biāo)后,通過scripts/kconfig/Makefile中對Kconfig的定義可知,最后執(zhí)行:
mconfarch/$(SRCARCH)/Kconfig
而對于conf和xconf等都有類似的過程,所以總結(jié)起來:當(dāng)make %config時,內(nèi)核根目錄的頂層Makefile會臨時編譯出scripts/kconfig中的工具程序conf/mconf/qconf等負(fù)責(zé)對arch/$(SRCARCH)/Kconfig文件進(jìn)行解析。這個Kconfig又通過source標(biāo)記調(diào)用各個目錄下的Kconfig文件構(gòu)建出一個Kconfig樹,使得工具程序構(gòu)建出整個內(nèi)核的配置界面。在配置結(jié)束后,工具程序就會生成我們常見的.config文件。
三、在內(nèi)核中添加自己的模塊
雖然內(nèi)核Makefile體系很是復(fù)雜,但是這種復(fù)雜帶來的確是開發(fā)時的便利。其實內(nèi)核Makefile體系之所以復(fù)雜,其中的一個原因就是為了方便擴(kuò)展。對于一個開發(fā)者來要在內(nèi)核中添加自己的一個驅(qū)動代碼是非常簡單的事情。
一般來說,對于一個新驅(qū)動代碼的添加,驅(qū)動工程師只需要在內(nèi)核源碼的drivers目錄的相應(yīng)子目錄下添加新設(shè)備驅(qū)動源碼,并增加或修改該目錄下的Kconfig和Makefile文件即可。
比如你已經(jīng)寫好了一個針對TI 的AM33XX芯片的LED的驅(qū)動程序,名為am33xx_led.c。
(1)將驅(qū)動源碼am33xx_led.c等文件復(fù)制到linux-X.Y.Z/drivers/char目錄。
(2)在該目錄下的Kconfig文件中添加LED驅(qū)動的配置選項:
config AM33XX_LED
bool "Support for am33xx led
drivers"
depends on ?SOC_OMAPAM33XX
default n
---help---
Say Y here if you want to support for?AM33XX?LED drivers.
(3)在該目錄下的Makefile文件中添加對LED驅(qū)動的編譯:
obj-$(CONFIG_AM33XX_LED)?? += ?am33xx_led.o
這樣你就可以在make menuconfig的時候看到這個配置選項,并進(jìn)行配置了。
當(dāng)然,上面的例子只是一個意思,對于Kconfig文件和Makefile的詳細(xì)語法,請參考內(nèi)核文檔:Documentation/kbuild/makefile.txt
四 、在內(nèi)核Makefile上對讀者的建議
這個復(fù)雜的Makefile體系體現(xiàn)了很多優(yōu)秀程序共有的設(shè)計思想,對于我們今后的程序設(shè)計上有很多值得借鑒的地方。比如:模塊化設(shè)計、簡化編程接口,使得自行添加模塊更加的簡潔。閱讀分析這樣復(fù)雜的Makefile對于學(xué)習(xí)和編寫Makefile和shell腳本有很好的參考價值。如果你正在學(xué)習(xí)Makefile的編寫和閱讀,那你可以耐心的分析一下內(nèi)核的Makefile體系,只要你認(rèn)真分析了一兩個目標(biāo)的實現(xiàn),你會發(fā)現(xiàn)當(dāng)你在閱讀一些小軟件的Makefile時已經(jīng)是輕車熟路了。特別是現(xiàn)在很多芯片的開發(fā)包都是以SDK包的形式發(fā)布的,而這些軟件包都是通過Makefile體系來實現(xiàn)自動編譯和配置的,所以熟悉Makefile是每個Linux開發(fā)者都需要做到的。
總結(jié)
以上是生活随笔為你收集整理的linux 内核 企鹅,Linux 内核 Makefile 体系简单分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 5G套餐每月资费多少?汇总移动、电信、联
- 下一篇: linux php cpu,获取Linu