歡迎您光臨本站 註冊首頁

內核配置淺析-zt

←手機掃碼閱讀     火星人 @ 2014-03-26 , reply:0

隨著 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 中,它的格式為:





給出本配置選項的名稱, 對應配置變數, 對應配置幫助信息。在幫助信息中,首先簡單描述此功能,其次說明選擇了此功能後會有什麼效果,不選擇又有什麼效果,最後,不要忘了寫上"如果不清楚,選擇 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/

[火星人 ] 內核配置淺析-zt已經有480次圍觀

http://coctec.com/docs/linux/show-post-190440.html