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