1. 程式人生 > >Linux kernel config and makefile system

Linux kernel config and makefile system

命令 原因 bug 匯編 tid asp excludes ted dex

轉載自:http://blog.csdn.net/dreamxu/article/details/6125545

http://www-900.ibm.com/developerWorks/cn/linux/kernel/l-kerconf/
上面這篇文章針對的系統相對較老點. 後來又找到了一篇新的文章:

http://blog.csdn.net/estate66/archive/2010/09/15/5886816.aspx

?

因為在2.6.36的內核中,已經沒有config.in文件。取而代之的是Kconfig文件。所以說前面的文章較老,但對於整個內核的編譯系統的把握非常有幫助。

?

這裏我先貼了第一篇文章。後面一篇在後面。
2003?年?2?月

隨著?Linux?操作系統的廣泛應用,特別是?Linux?在嵌入式領域的發展。越來越多的人開始投身到?Linux?內核級的開發中。面對日益龐大的?Linux?內核源碼,開發人員在完畢自己的內核代碼後,都將面臨著相同的問題,即怎樣將源碼融入到?Linux?內核中,增加相應的?Linux?配置選項。並終於被編譯進?Linux?內核。

這就須要了解?Linux?的內核配置系統。

眾所周知。Linux?內核是由分布在全球的?Linux?愛好者共同開發的,Linux?內核每天都面臨著很多新的變化。

可是。Linux?內核的組織並沒有出現混亂的現象,反而顯得非常的簡潔,並且具有非常好的擴展性,開發人員能夠非常方便的向?Linux?內核中增加新的內容。原因之中的一個就是?Linux?採用了模塊化的內核配置系統。從而保證了內核的擴展性。



本文首先分析了?Linux?內核中的配置系統結構,然後,解釋了?Makefile?和配置文件的格式以及配置語句的含義。最後。通過一個簡單的樣例--TEST?Driver。詳細說明怎樣將自行開發的代碼增加到?Linux?內核中。在下面的文章中,不可能解釋全部的功能和命令,僅僅對那些經常使用的進行解釋。至於那些沒有討論到的。請讀者參考後面的參考文獻。

1.?配置系統的基本結構

Linux內核的配置系統由三個部分組成,各自是:

Makefile:分布在?Linux?內核源碼中的?Makefile,定義?Linux?內核的編譯規則。?
配置文件(config.in):給用戶提供配置選擇的功能;?
配置工具:包括配置命令解釋器(對配置腳本中使用的配置命令進行解釋)和配置用戶界面(提供基於字符界面、基於?Ncurses?圖形界面以及基於?Xwindows?圖形界面的用戶配置界面。各自相應於?Make?config、Make?menuconfig?和?make?xconfig)。

這些配置工具都是使用腳本語言,如?Tcl/TK、Perl?編寫的(也包括一些用?C?編寫的代碼)。本文並非對配置系統本身進行分析。而是介紹怎樣使用配置系統。

所以,除非是配置系統的維護者,一般的內核開發人員無須了解它們的原理,僅僅須要知道怎樣編寫?Makefile?和配置文件就能夠。所以,在本文中,我們僅僅對?Makefile?和配置文件進行討論。另外,凡是涉及到與詳細?CPU?體系結構相關的內容,我們都以?ARM?為例,這樣不僅能夠將討論的問題明白化,並且對內容本身不產生影響。

2.?Makefile

2.1?Makefile?概述

Makefile?的作用是依據配置的情況,構造出須要編譯的源文件列表。然後分別編譯,並把目標代碼鏈接到一起。終於形成?Linux?內核二進制文件。



因為?Linux?內核源碼是依照樹形結構組織的,所以?Makefile?也被分布在文件夾樹中。

Linux?內核中的?Makefile?以及與?Makefile?直接相關的文件有:

Makefile:頂層?Makefile。是整個內核配置、編譯的整體控制文件。?
.config:內核配置文件,包括由用戶選擇的配置選項。用來存放內核配置後的結果(如?make?config)。?
arch/*/Makefile:位於各種?CPU?體系文件夾下的?Makefile,如?arch/arm/Makefile,是針對特定平臺的?Makefile。?
各個子文件夾下的?Makefile:比方?drivers/Makefile,負責所在子文件夾下源碼的管理。?
Rules.make:規則文件,被全部的?Makefile?使用。?
用戶通過?make?config?配置後,產生了?.config。頂層?Makefile?讀入?.config?中的配置選擇。頂層?Makefile?有兩個基本的任務:產生?vmlinux?文件和內核模塊(module)。為了達到此目的,頂層?Makefile?遞歸的進入到內核的各個子文件夾中,分別調用位於這些子文件夾中的?Makefile。至於究竟進入哪些子文件夾,取決於內核的配置。在頂層?Makefile?中。有一句:include?arch/$(ARCH)/Makefile,包括了特定?CPU?體系結構下的?Makefile,這個?Makefile?中包括了平臺相關的信息。



位於各個子文件夾下的?Makefile?相同也依據?.config?給出的配置信息,構造出當前配置下須要的源文件列表。並在文件的最後有?include?$(TOPDIR)/Rules.make。

Rules.make?文件起著非常關鍵的數據,它定義了全部?Makefile?共用的編譯規則。比方。假設須要將本文件夾下全部的?c?程序編譯成匯編代碼,須要在?Makefile?中有下面的編譯規則:

????????%.s:?%.c
????????$(CC)?$(CFLAGS)?-S?$<?-o?$@
????????
有非常多子文件夾下都有相同的要求,就須要在各自的?Makefile?中包括此編譯規則。這會比較麻煩。而?Linux?內核中則把此類的編譯規則統一放置到?Rules.make?中。並在各自的?Makefile?中包括進了?Rules.make(include?Rules.make),這樣就避免了在多個?Makefile?中反復相同的規則。

對於上面的樣例,在?Rules.make?中相應的規則為:

????????%.s:?%.c
????????$(CC)?$(CFLAGS)?$(EXTRA_CFLAGS)?$(CFLAGS_$(*F))?$(CFLAGS_$@)?-S?$<?-o?$@
????????
2.2?Makefile?中的變量

頂層?Makefile?定義並向環境中輸出了很多變量。為各個子文件夾下的?Makefile?傳遞一些信息。有些變量。比方?SUBDIRS,不僅在頂層?Makefile?中定義並且賦初值,並且在?arch/*/Makefile?還作了擴充。



經常使用的變量有下面幾類:

1)?版本號信息
版本號信息有:VERSION,PATCHLEVEL,?SUBLEVEL,?EXTRAVERSION,KERNELRELEASE。版本號信息定義了當前內核的版本號。比方?VERSION=2。PATCHLEVEL=4,SUBLEVEL=18,EXATAVERSION=-rmk7。它們共同構成內核的發行版本號KERNELRELEASE:2.4.18-rmk7

2)?CPU?體系結構:ARCH
在頂層?Makefile?的開頭。用?ARCH?定義目標?CPU?的體系結構,比方?ARCH:=arm?等。很多子文件夾的?Makefile?中,要依據?ARCH?的定義選擇編譯源文件的列表。



3)?路徑信息:TOPDIR,?SUBDIRS
TOPDIR?定義了?Linux?內核源碼所在的根文件夾。

比如,各個子文件夾下的?Makefile?通過?$(TOPDIR)/Rules.make?就能夠找到?Rules.make?的位置。
SUBDIRS?定義了一個文件夾列表。在編譯內核或模塊時,頂層?Makefile?就是依據?SUBDIRS?來決定進入哪些子文件夾。

SUBDIRS?的值取決於內核的配置,在頂層?Makefile?中?SUBDIRS?賦值為?kernel?drivers?mm?fs?net?ipc?lib;依據內核的配置情況,在?arch/*/Makefile?中擴充了?SUBDIRS?的值,參見4)中的樣例。



4)?內核組成信息:HEAD,?CORE_FILES,?NETWORKS,?DRIVERS,?LIBS
Linux?內核文件?vmlinux?是由下面規則產生的:


vmlinux:?$(CONFIGURATION)?init/main.o?init/version.o?linuxsubdirs
$(LD)?$(LINKFLAGS)?$(HEAD)?init/main.o?init/version.o?/
--start-group?/
$(CORE_FILES)?/
$(DRIVERS)?/
$(NETWORKS)?/
$(LIBS)?/
--end-group?/
-o?vmlinux

能夠看出。vmlinux?是由?HEAD、main.o、version.o、CORE_FILES、DRIVERS、NETWORKS?和?LIBS?組成的。這些變量(如?HEAD)都是用來定義連接生成?vmlinux?的目標文件和庫文件列表。

當中。HEAD在arch/*/Makefile?中定義,用來確定被最先鏈接進?vmlinux?的文件列表。比方,對於?ARM?系列的?CPU,HEAD?定義為:?
HEAD????????????:=?arch/arm/kernel/head-$(PROCESSOR).o?/
???????????????????arch/arm/kernel/init_task.o

表明?head-$(PROCESSOR).o?和?init_task.o?須要最先被鏈接到?vmlinux?中。PROCESSOR?為?armv?或?armo,取決於目標?CPU。?CORE_FILES,NETWORK。DRIVERS?和?LIBS?在頂層?Makefile?中定義,並且由?arch/*/Makefile?依據須要進行擴充。?CORE_FILES?相應著內核的核心文件。有?kernel/kernel.o。mm/mm.o,fs/fs.o,ipc/ipc.o,能夠看出,這些是組成內核最為關鍵的文件。同一時候。arch/arm/Makefile?對?CORE_FILES?進行了擴充:

#?arch/arm/Makefile

#?If?we?have?a?machine-specific?directory,?then?include?it?in?the?build.
MACHDIR?????????:=?arch/arm/mach-$(MACHINE)
ifeq?($(MACHDIR),$(wildcard?$(MACHDIR)))
SUBDIRS?????????+=?$(MACHDIR)
CORE_FILES??????:=?$(MACHDIR)/$(MACHINE).o?$(CORE_FILES)
endif

HEAD????????????:=?arch/arm/kernel/head-$(PROCESSOR).o?/
???????????????????arch/arm/kernel/init_task.o
SUBDIRS?????????+=?arch/arm/kernel?arch/arm/mm?arch/arm/lib?arch/arm/nwfpe
CORE_FILES??????:=?arch/arm/kernel/kernel.o?arch/arm/mm/mm.o?$(CORE_FILES)
LIBS????????????:=?arch/arm/lib/lib.a?$(LIBS)


5)?編譯信息:CPP,?CC,?AS,?LD,?AR,CFLAGS,LINKFLAGS
在?Rules.make?中定義的是編譯的通用規則,詳細到特定的場合。須要明白給出編譯環境,編譯環境就是在以上的變量中定義的。針對交叉編譯的要求。定義了?CROSS_COMPILE。

比方:


CROSS_COMPILE???=?arm-linux-
CC??????????????=?$(CROSS_COMPILE)gcc
LD??????????????=?$(CROSS_COMPILE)ld
......

CROSS_COMPILE?定義了交叉編譯器前綴?arm-linux-,表明全部的交叉編譯工具都是以?arm-linux-?開頭的,所以在各個交叉編譯器工具之前,都增加了?$(CROSS_COMPILE),以組成一個完整的交叉編譯工具文件名稱,比方?arm-linux-gcc。


CFLAGS?定義了傳遞給?C?編譯器的參數。


LINKFLAGS?是鏈接生成?vmlinux?時,由鏈接器使用的參數。LINKFLAGS?在?arm/*/Makefile?中定義。比方:

#?arch/arm/Makefile

LINKFLAGS???????:=-p?-X?-T?arch/arm/vmlinux.lds


6)?配置變量CONFIG_*
.config?文件裏有很多的配置變量等式,用來說明用戶配置的結果。

比如?CONFIG_MODULES=y?表明用戶選擇了?Linux?內核的模塊功能。
.config?被頂層?Makefile?包括後,就形成很多的配置變量,每一個配置變量具有確定的值:y?表示本編譯選項相應的內核代碼被靜態編譯進?Linux?內核;m?表示本編譯選項相應的內核代碼被編譯成模塊。n?表示不選擇此編譯選項;假設根本就沒有選擇。那麽配置變量的值為空。

2.3?Rules.make?變量

前面講過,Rules.make?是編譯規則文件。全部的?Makefile?中都會包括?Rules.make。Rules.make?文件定義了很多變量,最為重要是那些編譯、鏈接列表變量。

O_OBJS,L_OBJS,OX_OBJS。LX_OBJS:本文件夾下須要編譯進?Linux?內核?vmlinux?的目標文件列表,當中?OX_OBJS?和?LX_OBJS?中的?"X"?表明目標文件使用了?EXPORT_SYMBOL?輸出符號。



M_OBJS。MX_OBJS:本文件夾下須要被編譯成可裝載模塊的目標文件列表。相同,MX_OBJS?中的?"X"?表明目標文件使用了?EXPORT_SYMBOL?輸出符號。

O_TARGET,L_TARGET:每一個子文件夾下都有一個?O_TARGET?或?L_TARGET,Rules.make?首先從源碼編譯生成?O_OBJS?和?OX_OBJS?中全部的目標文件。然後使用?$(LD)?-r?把它們鏈接成一個?O_TARGET?或?L_TARGET。O_TARGET?以?.o?結尾,而?L_TARGET?以?.a?結尾。



2.4?子文件夾?Makefile

子文件夾?Makefile?用來控制本級文件夾下面源碼的編譯規則。我們通過一個樣例來解說子文件夾?Makefile?的組成:

#
#?Makefile?for?the?linux?kernel.
#
#?All?of?the?(potential)?objects?that?export?symbols.
#?This?list?comes?from?‘grep?-l?EXPORT_SYMBOL?*.[hc]‘.

export-objs :=?tc.o

#?Object?file?lists.

obj-y :=
obj-m :=
obj-n :=
obj- :=

obj-$(CONFIG_TC)?+=?tc.o
obj-$(CONFIG_ZS)?+=?zs.o
obj-$(CONFIG_VT)?+=?lk201.o?lk201-map.o?lk201-remap.o

#?Files?that?are?both?resident?and?modular:?remove?from?modular.

obj-m :=?$(filter-out?$(obj-y),?$(obj-m))

#?Translate?to?Rules.make?lists.

L_TARGET :=?tc.a

L_OBJS :=?$(sort?$(filter-out?$(export-objs),?$(obj-y)))
LX_OBJS :=?$(sort?$(filter?????$(export-objs),?$(obj-y)))
M_OBJS :=?$(sort?$(filter-out?$(export-objs),?$(obj-m)))
MX_OBJS :=?$(sort?$(filter?????$(export-objs),?$(obj-m)))

include?$(TOPDIR)/Rules.make

a)?凝視
對?Makefile?的說明和解釋,由#開始。



b)?編譯目標定義
相似於?obj-$(CONFIG_TC)?+=?tc.o?的語句是用來定義編譯的目標,是子文件夾?Makefile?中最重要的部分。編譯目標定義那些在本子文件夾下。須要編譯到?Linux?內核中的目標文件列表。為了僅僅在用戶選擇了此功能後才編譯。全部的目標定義都融合了對配置變量的推斷。
前面說過,每一個配置變量取值範圍是:y,n,m?和空。obj-$(CONFIG_TC)?分別相應著?obj-y,obj-n,obj-m。obj-。假設?CONFIG_TC?配置為?y。那麽?tc.o?就進入了?obj-y?列表。

obj-y?為包括到?Linux?內核?vmlinux?中的目標文件列表;obj-m?為編譯成模塊的目標文件列表;obj-n?和?obj-?中的文件列表被忽略。配置系統就依據這些列表的屬性進行編譯和鏈接。
export-objs?中的目標文件都使用了?EXPORT_SYMBOL()?定義了公共的符號。以便可裝載模塊使用。

在?tc.c?文件的最後部分。有?"EXPORT_SYMBOL(search_tc_card);",表明?tc.o?有符號輸出。
這裏須要指出的是,對於編譯目標的定義。存在著兩種格式,各自是老式定義和新式定義。

老式定義就是前面?Rules.make?使用的那些變量,新式定義就是?obj-y,obj-m。obj-n?和?obj-。Linux?內核推薦使用新式定義,只是因為?Rules.make?不理解新式定義,須要在?Makefile?中的適配段將其轉換成老式定義。

c)?適配段
適配段的作用是將新式定義轉換成老式定義。在上面的樣例中,適配段就是將?obj-y?和?obj-m?轉換成?Rules.make?能夠理解的?L_TARGET。L_OBJS,LX_OBJS,M_OBJS,MX_OBJS。
L_OBJS?:=?$(sort?$(filter-out?$(export-objs),?$(obj-y)))?定義了?L_OBJS?的生成方式:在?obj-y?的列表中過濾掉?export-objs(tc.o)。然後排序並去除反復的文件名稱。這裏使用到了?GNU?Make?的一些特殊功能,詳細的含義可參考?Make?的文檔(info?make)。

d)?include?$(TOPDIR)/Rules.make

3.?配置文件

3.1?配置功能概述

除了?Makefile?的編寫。另外一個重要的工作就是把新功能增加到?Linux?的配置選項中,提供此項功能的說明,讓用戶有機會選擇此項功能。

全部的這些都須要在?config.in?文件裏用配置語言來編寫配置腳本。?
在?Linux?內核中。配置命令有多種方式:

配置命令?解釋腳本?
Make?config,?make?oldconfig?scripts/Configure?
Make?menuconfig?scripts/Menuconfig?
Make?xconfig?scripts/tkparse?

以字符界面配置(make?config)為例,頂層?Makefile?調用?scripts/Configure,?依照?arch/arm/config.in?來進行配置。命令執行完後產生文件?.config,當中保存著配置信息。

下一次再做?make?config?將產生新的?.config?文件,原?.config?被改名為?.config.old

3.2?配置語言

1)?頂層菜單
mainmenu_name?/prompt/?/prompt/?是用‘或"包圍的字符串,‘與"的差別是‘…‘中可使用$引用變量的值。

mainmenu_name?設置最高層菜單的名字,它僅僅在?make?xconfig?時才會顯示。

2)?詢問語句?

????bool????????????/prompt/?/symbol/
????????hex?????????????/prompt/?/symbol/?/word/
????????int?????????????/prompt/?/symbol/?/word/
????????string??????????/prompt/?/symbol/?/word/
????????tristate????????/prompt/?/symbol/

詢問語句首先顯示一串提示符?/prompt/,等待用戶輸入。並把輸入的結果賦給?/symbol/?所代表的配置變量。不同的詢問語句的差別在於它們接受的輸入數據類型不同。比方?bool?接受布爾類型(?y?或?n?),hex?接受?16?進制數據。

有些詢問語句還有第三個參數?/word/。用來給出缺省值。

3)?定義語句?

????????define_bool?????/symbol/?/word/
????????define_hex??????/symbol/?/word/
????????define_int??????/symbol/?/word/
????????define_string???/symbol/?/word/
????????define_tristate?/symbol/?/word/

不同於詢問語句等待用戶輸入。定義語句顯式的給配置變量?/symbol/?賦值?/word/。

4)?依賴語句?

????????dep_bool????????/prompt/?/symbol/?/dep/?...
????????dep_mbool???????/prompt/?/symbol/?/dep/?...
????????dep_hex?????????/prompt/?/symbol/?/word/?/dep/?...
????????dep_int?????????/prompt/?/symbol/?/word/?/dep/?...
????????dep_string??????/prompt/?/symbol/?/word/?/dep/?...
????????dep_tristate????/prompt/?/symbol/?/dep/?...

與詢問語句相似,依賴語句也是定義新的配置變量。

不同的是,配置變量/symbol/的取值範圍將依賴於配置變量列表/dep/?…。這就意味著:被定義的配置變量所相應功能的取舍取決於依賴列表所相應功能的選擇。以dep_bool為例,假設/dep/?…列表的全部配置變量都取值y,則顯示/prompt/。用戶可輸入隨意的值給配置變量/symbol/,可是僅僅要有一個配置變量的取值為n,則/symbol/被強制成n。


不同依賴語句的差別在於它們由依賴條件所產生的取值範圍不同。

5)?選擇語句


choice??????????/prompt/?/word/?/word/

choice?語句首先給出一串選擇列表。供用戶選擇當中一種。比方?Linux?for?ARM?支持多種基於?ARM?core?的?CPU,Linux?使用?choice?語句提供一個?CPU?列表,供用戶選擇:

?????????choice?‘ARM?system?type‘?/
????????"Anakin?????????????????CONFIG_ARCH_ANAKIN?/
?????????Archimedes/A5000???????CONFIG_ARCH_ARCA5K?/
?????????Cirrus-CL-PS7500FE?????CONFIG_ARCH_CLPS7500?/
……
?????????SA1100-based???????????CONFIG_ARCH_SA1100?/
?????????Shark??????????????????CONFIG_ARCH_SHARK"?RiscPC
?????????
Choice?首先顯示?/prompt/,然後將?/word/?分解成前後兩個部分,前部分為相應選擇的提示符,後部分是相應選擇的配置變量。用戶選擇的配置變量為?y,其余的都為?n。



6)?if語句


????????if?[?/expr/?]?;?then
??????????/statement/?
??????????...
????????fi
????????
????????if?[?/expr/?]?;?then
??????????/statement/
??????????...
????????else
??????????/statement/
??????????...
????????fi
????????
if?語句對配置變量(或配置變量的組合)進行推斷,並作出不同的處理。推斷條件?/expr/?能夠是單個配置變量或字符串,也能夠是帶操作符的表達式。操作符有:=,!=,-o,-a?等。



7)?菜單塊(menu?block)語句?

mainmenu_option?next_comment
comment?‘…..‘

endmenu

引入新的菜單。在向內核增加新的功能後,須要相應的增加新的菜單,並在新菜單下給出此項功能的配置選項。

Comment?後帶的凝視就是新菜單的名稱。全部歸屬於此菜單的配置選項語句都寫在?comment?和?endmenu?之間。



8)?Source?語句
source?/word/
/word/?是文件名稱,source?的作用是調入新的文件。

3.3?缺省配置

Linux?內核支持非常多的硬件平臺,對於詳細的硬件平臺而言,有些配置就是必需的,有些配置就沒必要的。

另外,新增加功能的正常執行往往也須要一定的先決條件。針對新功能,必須作相應的配置。因此,特定硬件平臺能夠正常執行相應著一個最小的基本配置,這就是缺省配置。

Linux?內核中針對每一個?ARCH?都會有一個缺省配置。

在向內核代碼增加了新的功能後,假設新功能對於這個?ARCH?是必需的,就要改動此?ARCH?的缺省配置。改動方法例如以下(在?Linux?內核根文件夾下):

備份?.config?文件?
cp?arch/arm/deconfig?.config?
改動?.config?
cp?.config?arch/arm/deconfig?
恢復?.config?
假設新增的功能適用於很多的?ARCH,僅僅要針對詳細的?ARCH,反復上面的步驟就能夠了。



3.4?help?file

大家都有這種經驗,在配置?Linux?內核時,遇到不懂含義的配置選項,能夠查看它的幫助。從中可得到選擇的建議。下面我們就看看怎樣給給一個配置選項增加幫助信息。

全部配置選項的幫助信息都在?Documentation/Configure.help?中,它的格式為:

<description>
<variable?name>
<help?file>

<description>?給出本配置選項的名稱。<variable?name>?相應配置變量。<help?file>?相應配置幫助信息。在幫助信息中,首先簡單描寫敘述此功能。其次說明選擇了此功能後會有什麽效果,不選擇又有什麽效果。最後,不要忘了寫上"假設不清楚,選擇?N(或者)Y",給不知所措的用戶以提示。

4.?實例

對於一個開發人員來說,將自己開發的內核代碼增加到?Linux?內核中,須要有三個步驟。

首先確定把自己開發代碼放入到內核的位置;其次,把自己開發的功能增加到?Linux?內核的配置選項中,使用戶能夠選擇此功能;最後,構建子文件夾?Makefile,依據用戶的選擇。將相應的代碼編譯到終於生成的?Linux?內核中去。下面,我們就通過一個簡單的樣例--test?driver,結合前面學到的知識,來說明怎樣向?Linux?內核中增加新的功能。

4.1?文件夾結構

test?driver?放置在?drivers/test/?文件夾下:

$cd?drivers/test
$tree
.
|--?Config.in
|--?Makefile
|--?cpu
|???|--?Makefile
|???`--?cpu.c
|--?test.c
|--?test_client.c
|--?test_ioctl.c
|--?test_proc.c
|--?test_queue.c
`--?test
????|--?Makefile
????`--?test.c
????
4.2?配置文件

1)?drivers/test/Config.in?

#
#?TEST?driver?configuration
#
mainmenu_option?next_comment
comment?‘TEST?Driver‘

bool?‘TEST?support‘?CONFIG_TEST
if?[?"$CONFIG_TEST"?=?"y"?];?then
??tristate?‘TEST?user-space?interface‘?CONFIG_TEST_USER
??bool?‘TEST?CPU?‘?CONFIG_TEST_CPU
fi

endmenu

因為?test?driver?對於內核來說是新的功能,所以首先創建一個菜單?TEST?Driver。

然後。顯示?"TEST?support",等待用戶選擇;接下來推斷用戶是否選擇了?TEST?Driver。假設是(CONFIG_TEST=y)。則進一步顯示子功能:用戶接口與?CPU?功能支持;因為用戶接口功能能夠被編譯成內核模塊,所以這裏的詢問語句使用了?tristate(因為?tristate?的取值範圍包括?y、n?和?m。m?就是相應著模塊)。

2)?arch/arm/config.in
在文件的最後增加:source?drivers/test/Config.in,將?TEST?Driver?子功能的配置納入到?Linux?內核的配置中。

4.3?Makefile

1)drivers/test/Makefile


#???????drivers/test/Makefile
#
#???????Makefile?for?the?TEST.
#

SUB_DIRS?????:=
MOD_SUB_DIRS?:=?$(SUB_DIRS)
ALL_SUB_DIRS?:=?$(SUB_DIRS)?cpu

L_TARGET?:=?test.a
export-objs?:=?test.o?test_client.o

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

subdir-$(CONFIG_TEST_CPU)???????+=?cpu

include?$(TOPDIR)/Rules.make

clean:
????????for?dir?in?$(ALL_SUB_DIRS);?do?make?-C?$$dir?clean;?done
????????rm?-f?*.[oa]?.*.flags
????????
drivers/test?文件夾下終於生成的目標文件是?test.a。在?test.c?和?test-client.c?中使用了?EXPORT_SYMBOL?輸出符號,所以?test.o?和?test-client.o?位於?export-objs?列表中。然後,依據用戶的選擇(詳細來說,就是配置變量的取值),構建各自相應的?obj-*?列表。因為?TEST?Driver?中包一個子文件夾?cpu。當?CONFIG_TEST_CPU=y(即用戶選擇了此功能)時,須要將?cpu?文件夾增加到?subdir-y?列表中。

2)drivers/test/cpu/Makefile?

#???????drivers/test/test/Makefile
#
#???????Makefile?for?the?TEST?CPU?
#

SUB_DIRS?????:=
MOD_SUB_DIRS?:=?$(SUB_DIRS)
ALL_SUB_DIRS?:=?$(SUB_DIRS)

L_TARGET?:=?test_cpu.a

obj-$(CONFIG_test_CPU)???????+=?cpu.o


include?$(TOPDIR)/Rules.make

clean:
????????rm?-f?*.[oa]?.*.flags
????????

3)drivers/Makefile?

……
subdir-$(CONFIG_TEST) +=?test
……
include?$(TOPDIR)/Rules.make

在?drivers/Makefile?中增加?subdir-$(CONFIG_TEST)+=?test。使得在用戶選擇?TEST?Driver?功能後,內核編譯時能夠進入?test?文件夾。



4)Makefile?

……
DRIVERS-$(CONFIG_PLD)?+=?drivers/pld/pld.o
DRIVERS-$(CONFIG_TEST)?+=?drivers/test/test.a
DRIVERS-$(CONFIG_TEST_CPU)?+=?drivers/test/cpu/test_cpu.a

DRIVERS?:=?$(DRIVERS-y)
……

在頂層?Makefile?中增加?DRIVERS-$(CONFIG_TEST)?+=?drivers/test/test.a?和?DRIVERS-$(CONFIG_TEST_CPU)?+=?drivers/test/cpu/test_cpu.a。

怎樣用戶選擇了?TEST?Driver,那麽?CONFIG_TEST?和?CONFIG_TEST_CPU?都是?y,test.a?和?test_cpu.a?就都位於?DRIVERS-y?列表中,然後又被放置在?DRIVERS?列表中。

在前面以前提到過。Linux?內核文件?vmlinux?的組成中包括?DRIVERS,所以?test.a?和?test_cpu.a?終於可被鏈接到?vmlinux?中。

5.?參考

Document/kbuild/makefiles.txt,Linux?Kernel?Source?code?
Document/kbuild/config-language.txt,Linux?Kernel?Source?code?
Contributing?to?the?Linux?Kernel--The?Linux?Configuration?System。Linux?Journal,http://www.linuxjournal.com/categories.php?op=newindex&catid=178?
Unreliable?Guide?To?Hacking?The?Linux?Kernel,Paul?Rusty?Russell。[email protected]?

?

?

?

?

當我們編寫完一個驅動後,我們要把它以模塊形式編譯或者直接編譯

進內核時,須要改動相關文件。當中最重要的便是kconfig ,makefile。

主要是分析一下三者之間的關系。然後就其語法簡要的談一下。

???? 當我們在內核源碼文件夾下執行make (或者make menuconfig等

命令)命令時。實際上是依據makefile 來進行編譯的。

我在mini2440

開發板上編寫了一個按鍵控制led燈的驅動。文件名稱為buttons_leds_z

hao.c屬於字符驅動。因此在/driver/char/文件夾下的makefile部分最

後增加一行

obj-$(CONFIG_BUTTONS_LEDS_ZHAO)????? +=

buttons_leds_zhao.o

例如以下:

obj-y??? += mem.o random.o tty_io.o n_tty.o tty_ioctl.o

tty_ldisc.o tty_buffer.o tty_port.o


obj-$(CONFIG_BFIN_JTAG_COMM)??? += bfin_jtag_comm.o


obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o

consolemap_deftbl.o


obj-$(CONFIG_HW_CONSOLE)??????? += vt.o defkeymap.o


obj-$(CONFIG_AUDIT)???????????? += tty_audit.o

obj-$(CONFIG_BUTTONS_LEDS_ZHAO)????? +=

buttons_leds_zhao.o

當中第一行obj-y? 中的y表示編譯進內核,而obj-$(CONFIG_LEGAC

Y_PTYS)? 中CONFIG_LEGACY_PTYS則表示一個變量。相似於我們C

語言中的變量。用$( )來表示,它一般能夠取三種值y ,m ,n.y表示

編譯進內核。而m則表示以模塊的方式進行編譯,n表示不編譯進內

核。

obj-y??? += 等號後面的.o後綴文件則是由該文件夾下的相應名稱的

.c文件編譯而來。


而上面CONFIG_LEGACY_PTYS變量的取值則是通過.config文件來集

中賦值的。.config部分內容例如以下

# Character devices?
#?
CONFIG_VT=y


CONFIG_CONSOLE_TRANSLATIONS=y


CONFIG_VT_CONSOLE=y


CONFIG_HW_CONSOLE=y

??
# CONFIG_VT_HW_CONSOLE_BINDING is not set

??
# CONFIG_DEVKMEM is not set


CONFIG_MINI2440_HELLO_MODULE=m


CONFIG_BUTTONS_LEDS_ZHAO=m


CONFIG_LEDS_MINI2440=m


CONFIG_MINI2440_BUTTONS=m


CONFIG_MINI2440_BUZZER=y


CONFIG_MINI2440_ADC=y


# CONFIG_SERIAL_NONSTANDARD is not set


???? 從上面幾行我們能夠看到。在makefile裏面的變量都是在.config中

賦值的。當我們在源碼文件夾下輸入make命令時,都是默認從.config

中讀入。

???? 因此。在輸入make之前,用ls? -a 查看一下是否有該文件。

對於

僅僅包括幾個文件的project來說。手動寫.config和makefile並非一件非常難

的事情。但假設是一個包括有幾百個文件的項目來說,則是一件比較困

難的事情。

能夠用autoconf來自己主動生成.config,automake來制作

makefile。看起來問題是解決的,但實際上,這種做法缺乏一定的靈活

性。不能實現按需定制的要求。假設要增加或刪掉某個驅動。將要在

.config文件裏找到相應的項進行改動。

非常的不方便。因此,便出現了

kconfig。

當我們在內核源碼文件夾下輸入make menuconfig時,出現例如以下內容:

.config - Linux Kernel v2.6.32.2 Configuration?
──────────────────────────────────────────────────────────────────────────────────────────────────
┌──────────────────────────────── Linux Kernel Configuration ─────────────────────────────────┐?
│? Arrow keys navigate the menu.? <Enter> selects submenus --->.? Highlighted letters are???? │?
│? hotkeys.? Pressing <Y> includes, <N> excludes, <M> modularizes features.? Press <Esc><Esc> │?
│? to exit, <?

> for Help, </> for Search.? Legend: [*] built-in? [ ] excluded? <M> module???? │?
│? < > module capable???????????????????????????????????????????????????????????????????????? │?
│ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ │?
│ │???????????? General setup? --->???????????????????????????????????????????????????????? │ │?
│ │???????? [*] Enable loadable module support? --->??????????????????????????????????????? │ │?
│ │???????? -*- Enable the block layer? --->??????????????????????????????????????????????? │ │?
│ │???????????? System Type? --->?????????????????????????????????????????????????????????? │ │?
│ │???????????? Bus support? --->?????????????????????????????????????????????????????????? │ │?
│ │???????????? Kernel Features? --->?????????????????????????????????????????????????????? │ │?
│ │???????????? Boot options? --->????????????????????????????????????????????????????????? │ │?
│ │???????????? CPU Power Management? --->????????????????????????????????????????????????? │ │?
│ │???????????? Floating point emulation? --->????????????????????????????????????????????? │ │?
│ │???????????? Userspace binary formats? --->????????????????????????????????????????????? │ │?
│ │???????????? Power management options? --->????????????????????????????????????????????? │ │?
│ │???????? [*] Networking support? --->??????????????????????????????????????????????????? │ │?
│ │???????????? Device Drivers? --->??????????????????????????????????????????????????????? │ │?
│ │???????????? File systems? --->????????????????????????????????????????????????????????? │ │?
│ └─────────┴(+)────────────────────────────────────────────────────────────────────────────┘ │?
├─────────────────────────────────────────────────────────────────────────────────────────────┤
│????????????????????????????? <Select>??? < Exit >??? < Help >?????????????????????????????? │?
└─────────────────────────────────────────────────────────────────────────────────────────────┘

????????????? 它是通過讀取在內核源碼文件夾下的Kconfig文件來配置的。

在/drivers/char/下的文件夾kconfig部分內容例如以下:

config DEVKMEM?
??????? bool "/dev/kmem virtual device support"?
??????? default y?
??????? help?
????????? Say Y here if you want to support the /dev/kmem device. The?
????????? /dev/kmem device is rarely used, but can be used for certain?
????????? kind of kernel debugging operations.?
????????? When in doubt, say "N".

config MINI2440_HELLO_MODULE?
??????? tristate "Mini2440 module sample"?
??????? depends on MACH_MINI2440?
??????? default m if MACH_MINI2440?
??????? help?
????????? Mini2440 module sample.

config BUTTONS_LEDS_ZHAO?
??????? tristate "Mini2440 button? and leds sample"?
??????? depends on MACH_MINI2440?
??????? default m if MACH_MINI2440?
??????? help?
????????? Mini2440? button and leds? module sample.


其詳細語法格式說明例如以下:

configkeyword是一個新的配置選項的入口???? 其後的選項MINI2440_H

ELLO_MODULE省略了CONFIG。完整的表示為CONFIG_MINI2440

_HELLO_MODULE,也即是當我們將該選項設置成y時。它將自己主動的將

.config的CONFIG_MINI2440_HELLO_MODULE=m改寫成

CONFIG_MINI2440_HELLO_MODULE=y。


緊接著的是菜單的屬性 最基本的有2種tristate ,boolean 。

tristate表

示三態:編譯進內核(y),編譯成模塊(m)。不編譯(n)。boolean 主

要有兩種y或ndepend則表示依賴項? default缺省的編譯選項 m表示默

認該文件表示以模塊方式編譯。後面的help是幫助信息,當我們選中

help菜單時就能夠看見,它沒必要的。隨著操作系統升級,編譯選項

達到幾千個。對於一般人來說,要搞清每一個選項是非常困難的,一般非常

多選項都是默認的。

??????? 總的來說。三者之間的關系例如以下:當我們在內核源碼文件夾下輸入

makemenuconfig時,在出現的菜單界面中選擇一項時。它會自己主動跟新

.config相應項的值。假設我們沒有選擇。則會在.config問下插入一行

凝視。相似於# CONFIG_SERIAL_NONSTANDARD is not set,當

我們輸入make時。依據makefile文件來編譯,makefile文件裏的變量

值則由.config來進行賦值操作。

僅僅僅僅在kconfig中增加選項,僅僅會在

菜單界面中顯示,即使此時選擇y或m。也不會編譯文件。還須要在

makefile文件裏依照規定增加相應行才幹進行編譯。

簡單圖解例如以下:

???????????

kconfig------->.config---------->makefile



Linux kernel config and makefile system