Linux內核配置系統-Kconfig和Makefile參數講解

本文主要介紹Linxu2.6的內核配置系統。

 

如果你瀏覽一下源代碼目錄,就可以發現源碼目錄及其子目錄中有很多的KConfig文件和Makefile文件。這些文件什麼作用呢?正是這些文件組成了Linux2.6的內核配置系統。

 

 

一、make menuconfig的背後------KConfig文件的組織

 

有沒有想過,我們make menuconfig後,顯示的那個菜單列表是怎麼來的?

帶着這個疑問,我們先來簡單學一下Kconfig文件的“語法”。

 

source 關鍵字:

用法:source <filename>

這個關鍵字相當於C語言裏的“include”關鍵字,source後面跟一個文件名,相當於把該文件的內容複製到當前位置。下面是源碼目錄的arch/arm目錄下Kconfig文件的部分內容。

 

通過這種source引用,可以引入很多其他子目錄中的Kconfig文件,而且引入的Kconfig文件中,還可以繼續通過source來引入下一級的Kconfig文件。這樣的結構就可以將所有的Kconfig文件包含進來。

 

一個菜單項(或叫配置項)的基本組成:config、bool(tristate)、default、prompt、help

一個簡單的菜單項:

其中,config關鍵字表示新定義一個菜單項,後面跟的是這個菜單項的名字(ARCH_IXP23XX)。bool標識這個菜單項是bool類型,也就是這一項只能有兩個值Y和N,此外還有一種最常用的類型,tristate三態型,這種類型的可以有三個值,Y/M/N,這三個值的意義在(上)篇中已經說過了。後面的“IXP23XX-based”是這個菜單項的描述,就是在make menuconfig時我們能看到的,如下圖:

在菜單列表裏我們並看不到一個菜單項的名字,而只能看到它的描述,因爲看它的描述更便於我們理解這個菜單項的意義,方便我們配置。關於菜單項的描述,還有一個prompt關鍵字,舉例說明其用法。比如下面兩段是等效的

----------------------------------

CONFIG MY_MENU

bool

prompt "this is my menu"

----------------------------------

CONFIG MY_MENU

bool "this is my menu"

----------------------------------

就是說,一個菜單項的描述,可以直接跟在其類型(bool)的後面來進行聲明,也可以由prompt關鍵字聲明。

關於default關鍵字,截圖中並未出現,但也是很常用的,它表明一個菜單項的默認值。如

default y

在進入菜單列表時,可以發現很多菜單項都有默認值,這些默認值就是通過Kconfig文件裏的default定義的。

還有一個help關鍵字,help關鍵字後面的內容是幫助信息,就是我們點擊右下角的heip時顯示的關於這個菜單項的幫助信息。下面是關於上圖所示的菜單項的幫助信息:

 

 

 

菜單項間的依賴關係:select和depends on

還拿上面的例子來說明,第三行"depends on MMU"。這一行是說,現在定義的"ARCH_IXP23XX"這個菜單項的值(Y/N)依賴於MMU這個菜單項的值。當MMU這個菜單項爲N時,ARCH_IXP23XX只能爲N。ARCH_IXP23XX的值必須“小於”MMU的值。(對於bool型,Y>N;對於tristate型,Y>M>N)。

select關鍵字的作用恰與depends on相反,它描述了一個反依賴的關係。以第五行"select PCI"爲例,PCI的值依賴於ARCH_IXP23XX。在定義PCI這個菜單項時,也要加上這樣一句:"depends on ARCH_IXP23XX"。

根據各菜單項之間的依賴關係,在make menuconfig時,系統會自動將這些相關聯的菜單項整理成菜單項與子菜單項的形式,如下圖

 

 

第二張圖中的菜單項都依賴於"Enable the block layer"對應的菜單項,所以系統將它們整理成子菜單項。只有"Enable the block layer"對應的菜單項不爲N時,這些子菜單項纔可以配置。

 

menu與endmenu關鍵字

這個關鍵字主要是爲了給菜單項分組,使菜單結構看起來更有條理。menu用來定義一個子菜單,這個子菜單裏包括一些相關的菜單項,在menu和endmenu關鍵字之間定義的菜單項都屬於這個子菜單。還以那上面兩張圖爲例,"Enable the block layer----->"菜單項下面的"system type--->"就是一個子菜單的名稱。將這個子菜單展開就可以看到這個子菜單包含的菜單項了。

menu "System type"

config ……

…………

config……

…………

config………

…………

…………

endmenu

這裏再額外解釋一下,在上面的圖中,"Enable the block layer--->"和"system type-->",這兩個雖然看起來很像,都可以展開,但其性質是不同的。前者是根據各菜單項間的依賴關係建立起來的,"Enable the block layer"本身就對應一個菜單項或者說配置項,它也有自己的值(Y/M/N),而"system type"則只是一個子菜單的名稱,它下面包含了一些相關的配置項,但他本身不對應某個配置項,因而沒有值(所以菜單列表中"system type--->"的前面沒有*或M這些符號)。

 

choices與endchoice關鍵字

跟menu與endmenu用法基本一樣,唯一的區別在於,choices定義的“子菜單”(應該叫選項表)中的多個菜單項只能有一個被選中,相當於menu定義一個可多選的子菜單,choices定義一個單選的子菜單。篇幅限制,不再截圖詳述。

 

if與endif關鍵字

這兩個真心不用解釋,原諒我直接略過。 

 

comment關鍵字

用來在菜單列表中插入一行文字,也是爲了優化菜單結構。

如上圖中的第四、五行,就是通過  comment "Processor Type"  和 comment "Processor Features"插入的。這兩行既不能展開,也不能被配置,他們只是爲菜單列表分段的一行文字。

 

 

終於把Kconfig中的關鍵字連圖帶字的解說完了,好累啊。(很多教材和博客上介紹這些關鍵字的時候都是隻有文字描述,而不結合make menuconfig後出現的菜單界面聯繫着說明,讀起來不夠直觀,現在我就把這些整理出來,供新手們快速掌握和理解這些關鍵字的作用)。大家現在可以試着去閱讀一個Kconfig文件了。

好了,對這些關鍵字有了認識之後,我們來說一下這個菜單列表的形成過程。運行make menuconfig後,系統的配置工具先分析與體系結構對應的/arch/ARCH/Kconfig
文件(這裏出現的ARCH參數在本文最後會講到。它其實指的就是所用的<cpu>),/arch/ARCH/Kconfig文件中定義了一個主菜單mainmenu,它除了包含一些配置項和配置菜單以外,還通過source語句引用了一系列其他子目錄中的Kconfig文件,被引用進來的Kconfig 文件內部可能再次通過source 引入下一級目錄中的Kconfig,系統就根據所有這些Kconfig文件中包含的菜單項(配置項)形成了菜單列表,然後根據用戶對各個菜單項設置的值,最後生成.config文件。

 

 

 

二、另一個重要角色------kbuild Makefile的介紹

 

Kconfig文件幫助用戶完成配置過程,而真正編譯內核則是在各個子目錄中的一系列Makefile共同完成的。Makefile中的重要語法就三個,比較好理解,這裏直接引用書中的內容。我把需要注意的地方用粗體標示。

引自 華清遠見嵌入式培訓中心 宋寶華 編著的《Linux設備驅動開發詳解》(這本書真的很好,需要電子版的同仁可以直接聯繫我):

(1)目標定義。
目標定義用來定義哪些內容要作爲模塊編譯,哪些要編譯並連接進內核。
例如:
obj-y += foo.o
表示要由foo.c 或者foo.s 文件編譯得到foo.o 並連接進內核,而obj-m 則表示該
文件要作爲模塊編譯。除了y、m以外的obj-x形式的目標都不會被編譯。
而更常見的做法是根據.config 文件的CONFIG_變量來決定文件的編譯方式,如
下所示:
obj-$(CONFIG_ISDN) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
除了obj-形式的目標以外,還有lib-y library庫、hostprogs-y 主機程序等目標,但
是基本都應用在特定的目錄和場合下。
(2)多文件模塊的定義。
如果一個模塊由多個文件組成,這時候應採用模塊名加-objs後綴或者-y後綴的形
式來定義模塊的組成文件。如下面的例子所示:
obj-$(CONFIG_EXT2_FS) += ext2.o
ext2-y := balloc.o bitmap.o
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
模塊的名字爲ext2,由balloc.o和bitmap.o兩個目標文件最終連接生成ext2.o 直
至ext2.ko 文件,是否包括xattr.o 取決於內核配置文件的配置情況。如果
CONFIG_EXT2_FS 的值是y 也沒有關係,在此過程中生成的 ext2.o 將被連接進
built-in.o最終連接進內核。這裏需要注意的一點是,
該kbuild Makefile所在的目錄中
不能再包含和模塊名相同的源文件如ext2.c/ext2.s。
或者寫成如-objs的形式:
obj-$(CONFIG_ISDN) += isdn.o
isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
(3)目錄層次的迭代。
示例:
obj-$(CONFIG_EXT2_FS) += ext2/
當CONFIG_EXT2_FS 的值爲y或m時,kbuild將會把ext2 目錄列入向下迭代的
目標中,具體ext2 目錄下的文件是要作爲模塊編譯還是鏈入內核由ext2 目錄下的
Makefile文件的內容決定。

 

引用結束。

上面所述的(3)特別關鍵,目錄層次的迭代使得整個Makefile系統呈現一個樹狀結構,條理清晰,加載新的編譯目錄也很方便。

 

 

 

三、牛刀初試

 

假如我們自己開發了一個新的模塊,要如何才能把我們自己的模塊加到配置系統中?上面已經介紹了Kconfig和Makefile文件的基本語法,爲了確保我們掌握了這兩種文件的配置方法,我們最好做一下練習,。這裏我要再次偷懶,直接COPY書中內容了。

引用開始:

下面講解一個綜合實例,假設我們要在內核源代碼drivers目錄下爲ARM體系結
構新增如下用於test driver 的樹型目錄:
|--test
|-- cpu
| -- cpu.c
|-- test.c
|-- test_client.c
|-- test_ioctl.c
|-- test_proc.c
|-- test_queue.c
在內核中增加目錄和子目錄,我們需爲相應的新增目錄創建Kconfig 和Makefile
文件,而新增目錄的父目錄中的Kconfig 和Makefile 文件也需要修改,以便新增的
Kconfig和Makefile文件能被引用。
在新增的test目錄下,應該包含如下Kconfig文件:
#
# TEST driver configuration
#
menu "TEST Driver "
comment " TEST Driver"
config CONFIG_TEST
bool "TEST support "
config CONFIG_TEST_USER
tristate "TEST user-space interface"
depends on CONFIG_TEST
endmenu
由於TEST driver 對於內核來說是新的功能,所以首先需要創建一個菜單TEST
Driver;然後顯示“TEST support”,等待用戶選擇;接下來判斷用戶是否選擇了TEST
Driver,如果是(CONFIG_TEST=y),則進一步顯示子功能:用戶接口與CPU功能支
持;由於用戶接口功能可以被編譯成內核模塊,所以這裏的詢問語句使用了tristate。
爲了使這個Kconfig文件能起作用,需要修改arch/arm/Kconfig文件,增加以下內
容:
source "drivers/test/Kconfig"
腳本中的source意味着引用新的Kconfig文件。
在新增的test目錄下,應該包含如下Makefile文件:
# drivers/test/Makefile
#
# Makefile for the TEST.
#
obj-$(CONFIG_TEST) += test.o test_queue.o test_client.o
obj-$(CONFIG_TEST_USER) += test_ioctl.o
obj-$(CONFIG_PROC_FS) += test_proc.o
obj-$(CONFIG_TEST_CPU) += cpu/
該腳本根據配置變量的取值構建obj-*列表。由於test目錄中包含一個子目錄cpu,
當CONFIG_ TEST_CPU=y時,需要將cpu目錄加入列表。
test目錄中的cpu子目錄也需包含如下的Makefile文件:
# drivers/test/test/Makefile
#
# Makefile for the TEST CPU
#
obj-$(CONFIG_TEST_CPU) += cpu.o
爲了使得整個test 目錄能夠被編譯命令作用到,test 目錄父目錄中的Makefile 文
件也需新增如下腳本:
obj-$(CONFIG_TEST) += test/
在drivers/Makefile中加入obj-$(CONFIG_TEST) += test/,使得用戶在進行內核編
譯時能夠進入test目錄。
增加了Kconfig和Makefile文件之後的新的test樹型目錄如下所示:
|--test
|-- cpu
| -- cpu.c
| -- Makefile
|-- test.c
|-- test_client.c
|-- test_ioctl.c
|-- test_proc.c
|-- test_queue.c
|-- Makefile
|-- Kconfig

 

 

 

 

 

 

 

附:(頂層Makefile中的ARCH參數、編譯ARM平臺Linux內核的方法)

源代碼目錄頂層目錄中的Makefile文件被稱作頂層Makefile,它裏面涉及到一個ARCH參數,還有一個CROSS_COMPILE參數,分別對應處理器內核架構和交叉編譯器。一般情況下,ARCH默認爲x86,CROSS_COMPILE默認也是x86平臺上的交叉編譯器。在執行make menuconfig,make bzImage,make modules等命令時,系統都會首先分析ARCH的值,根據選擇的平臺來執行相應操作。因此,如果想編譯ARM平臺的Linux內核,在輸入相應命令時要加上架構和交叉編譯器選項,如

make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig

 

make ARCH=arm CROSS_COMPILE=arm-linux- bzImage

make ARCH=arm CROSS_COMPILE=arm-linux- modules

 

如果直接將

ARCH=arm

CROSS_COMPILE=arm-linux-

這兩行添加到頂層Makefile的開頭,就可以將ARCH和CROSS_COMPILE的默認值改成"arm"和"arm-linux-"了。以後再編譯ARM平臺的Linux內核時就可以直接使用make menuconfig/bzImage/modules等命令,而不用再加"ARCH=arm CROSS_COMPILE=arm-linux-"。


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