Linux內核配置系統淺析























 



未顯示需要 JavaScript 的文檔選項


















 




級別: 初級


湯凱 (tangk73@hotmail.com),


2003 年 3 月 01 日


Your article abstract goes here. It may include trademark symbols for IBM or Java.

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


眾所周知,Linux 內核是由分佈在全球的 Linux 愛好者共同開發的,Linux 內核每天都面臨著許多新的變化。但是,Linux 內核的組織並沒有出現混亂的現象,反而顯得非常的簡潔,而且具有很好的擴展性,開發人員可以很方便的向 Linux 內核中增加新的內容。原因之一就是 Linux 採用了模塊化的內核配置系統,從而保證了內核的擴展性。


本文首先分析了 Linux 內核中的配置系統架構,然後,解釋了 Makefile 和配置檔案的格式以及配置語句的含義,最後,透過一個簡單的例子--TEST Driver,具體說明如何將自行開發的代碼加入到 Linux 內核中。在下面的文章中,不可能解釋所有的功能和命令,只對那些常用的進行解釋,至於那些沒有討論到的,請讀者參考後面的參考文獻。


1. 配置系統的基本架構


Linux內核的配置系統由三個部分組成,分別是︰



  1. Makefile︰分佈在 Linux 內核源代碼中的 Makefile,定義 Linux 內核的編譯規則;
  2. 配置檔案(config.in)︰給用戶提供配置選擇的功能;
  3. 配置工具︰包括配置命令解釋器(對配置腳本中使用的配置命令進行解釋)和配置用戶界面(提供基於字符界面、基於 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 直接相關的檔案有︰



  1. Makefile︰頂層 Makefile,是整個內核配置、編譯的總體控制檔案。
  2. .config︰內核配置檔案,包含由用戶選擇的配置選項,用來存放內核配置後的結果(如 make config)。
  3. arch/*/Makefile︰位於各種 CPU 體系目錄下的 Makefile,如 arch/arm/Makefile,是針對特定平台的 Makefile。
  4. 各個次目錄下的 Makefile︰比如 drivers/Makefile,負責所在次目錄下源代碼的管理。
  5. 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 oldconfigscripts/Configure
Make menuconfigscripts/Menuconfig
Make xconfigscripts/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 內核根目錄下)︰



  1. 備份 .config 檔案
  2. cp arch/arm/deconfig .config
  3. 修改 .config
  4. cp .config arch/arm/deconfig
  5. 恢復 .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 中。





參考資料



  • 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,rusty@rustcorp.com.au



關於作者












湯凱,透過 tangk73@hotmail.com可以跟他聯繫。


arrow
arrow
    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()