Linux Kconfig及Makefile學習

內核源碼樹的目錄下都有兩個文檔 Kconfig (2.4版本是Config.in)和Makefile。分佈到各目錄的Kconfig構成了一個分佈式的內核配置數據庫,每個Kconfig分別描述了 所屬目錄源文檔相關的內核配置菜單。在內核配置make menuconfig時,從Kconfig中讀出菜單,用戶選擇後保存到.config的內核配置文檔中。在內核編譯時,主Makefile調用這 個.config,就知道了用戶的選擇。


上面的內容說明了,Kconfig就是對應着內核的配置菜單。假如要想添加新的驅動到內核的源碼中,能夠修改Kconfig,這樣就能夠選擇這個驅動,假如想使這個驅動被編譯,要修改Makefile。所以,添加新的驅動時需要修改的文檔有兩種(注意不只是兩個)
*Kconfig
*Makefile

---------------------------------------------------------------------------------------------
Kconfig

1.先了解一下Kconfig的語法:
一個典型的內核配置菜單如下:
menu "Network device support"
config NETDEVICES
        bool "Enable Net Devices"
        depends on NET
        default y
       help
               This is help desciption。
...
endmenu
包含在menu/endmenu中的內容會成爲Network device support的子菜單。每一個子菜單項都是由config來定義的。congfig下方的那些bool、depends on、default、help等爲config的屬性,用於定義該菜單項的類型、依賴項、默認值、幫助信息等。

2. 補充說明一下類型定義部分:
每個config菜單項都要有類型定義: bool布爾類型、 tristate三態(內建、模塊、移除)、string字符串、 hex十六進制、 integer整型。
例如:
config HELLO_MODULE
bool "hello test module"
bool 類型的只能選中或不選中,顯示爲[ ]; tristate類型的菜單項多了編譯成內核模塊的選項,顯示爲< > , 假如選擇編譯成內核模塊,則會在.config中生成一個 CONFIG_HELLO_MODULE=m的配置,假如選擇內建,就是直接編譯成內核影響,就會在.config中生成一個 CONFIG_HELLO_MODULE=y的配置. hex十六進制類型顯示爲( )。

3. 目錄層次迭代
在Kconfig中有類似語句:source "drivers/usb/Kconfig"
用來包含(或嵌套)新的Kconfig文件,這樣便可以使各個目錄管理各自的配置內容,使不必把那些配置都寫在同一個文件裏,方便修改和管理。

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

Makefile

2.6內核的Makefile分爲5個組成部分:
       1. 最頂層的Makefile
       2. 內核的.config配置文件
       3.   在arch/$(ARCH) 目錄下的體系結構相關的Makefile 
       4. 在s目錄下的 Makefile.* 文件,是一些Makefile的通用規則 
       5. 各級目錄下的大概約500個kbuild Makefile文件

頂層的Makefile文件讀取 .config文件的內容,並總體上負責build內核和模塊。Arch Makefile則提供補充體系結構相關的信息。 s目錄下的Makefile文件包含了所有用來根據kbuild Makefile 構建內核所需的定義和規則。


Kbuild Makefile
對於Makefiles的不同組成部分,有一些不同的語法規則。針對的對象也不同,對於大部分內核模塊或設備驅動的開發者和使用者來說,最常接觸到的就是 各層目錄下基於kbuild架構的kbuild Makefile文件。Kbuild Makefile核心內容主要包括:

1.目標定義
目標定義就是用來定義哪些內容要做爲模塊編譯,哪些要編譯鏈接進內核。如:

obj-y += foo.o

表示要由foo.c或者foo.s文件編譯得到 foo.o並鏈接進內核,而obj-m則表示該文件要作爲模塊編譯。 除了y,m以外的obj-x形式的目標都不會被編譯。而更常見的做法是根據.config文件的CONFIG_ 變量來決定文件的編譯方式(該變量如何起作用見文末另一篇文章的鏈接),如:
obj-$(CONFIG_EXT2) += ext2.o

除了obj-形式的目標以外,還有lib-y library庫,hostprogs-y 主機程序等目標,但是基本都應用在特定的目錄和場合下。


2.多文件模塊的定義 
最簡單的kbuild Makefile如上一節一句話的形式就夠了,如果一個模塊由多個文件組成,那麼稍微複雜一些,採用模塊名加 –objs後綴或者 –y後綴的形式來定義模塊的組成文件。如以下例子:
obj-$(CONFIG_EXT2) += ext2.o
ext2-y := balloc.o bitmap.o

或者寫成如-objs的形式:
obj-$(CONFIG_EXT2) += ext2.o
ext2-objs := balloc.o bitmap.o

模塊的名字爲ext2,如果CONFIG_EXT2 的值是m,由balloc.o和bitmap.o兩個目標文件最終鏈接生成ext2.o 直至ext2.ko文件,如果CONFIG_EXT2的值是y,生成的 ext2.o將被鏈接進built-in.o最終鏈接進內核。


3.目錄層次的迭代
如下例:
obj-$(CONFIG_EXT2) += ext2/

如果CONFIG_EXT2 的值爲y或m,kbuild將會將ext2目錄列入向下迭代的目標中。

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

模塊的編譯

編譯模塊的時候,你可以將模塊放在代碼樹中,用Make modules的方式來編譯你的模塊
此時Makefile內容很簡單,例如:obj-$(CONFIG_EXT2) += ext2.o 即可。

也可以將模塊相關文件目錄放在代碼樹以外的位置,用如下命令來編譯模塊:
make -C <path to kernel src> M=$PWD modules

‘-C’指定代碼樹的位置,M=$PWD 或 M=`PWD` 告訴kbuild回到當前目錄來執行build操作。
當然,我們也可以爲其寫一個Makefile,這裏介紹一個教通用的Makefile(2.6版本):

# Makefile2.6 
ifneq ($(KERNELRELEASE),) 
#kbuild syntax. dependency relationshsip of files and target modules are listed here. 
obj-m := hello.o 
hello-objs := hello.o   
else 
PWD := $(shell pwd) 
KDIR := /lib/modules/$(shell uname -r)/build 
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean: 
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions 
endif 

此例子驅動目錄叫做hello,實際中需要將下面的hello換成自己的目錄名稱。其中代碼樹路徑是自動獲取的。之後在目錄下直接執行make命令即可,不再用敲上面一大長串命令。

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

在添加新驅動時,需要創建Kconfig、Makefile文件,且需要修改父目錄Kconfig、Makefile這兩個文件以便將自己的驅動包含進去。

例子如下:

爲Android內核添加新驅動,並提供menuconfig選項

爲Android的Linux內核2.6.25添加驅動。

1. 在drives目錄下添加hello目錄,內含hello.c Kconfig Makefile

hello.c內容:
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
        printk(KERN_ALERT"Hello, world\n");
        return 0;
}
static void hello_exit(void)
{

        printk(KERN_ALERT"Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

Kconfig內容:
config HELLO
tristate "Hello Driver added by Dong"
default n
help
   test for adding driver to menuconfig.

MakeFile內容:
obj-$(CONFIG_HELLO) += hello.o


2. 上面的Kconfig文件再加上下面的兩個配置,可使hello項出現在配置菜單中。
在arch/arm/Kconfig menu "Device Drivers" endmenu之間添加
source "drivers/hello/Kconfig"

在drivers/Kconfig menu "Device Drivers" endmenu之間添加
source "drivers/hello/Kconfig"

(不知爲什麼arch/arm/Kconfig中竟然含有Drivers裏Kconfig內容的一個複本,
實驗證明只對drivers/Kconfig中修改內容無效。)

3.修改Drivers目錄下的Makefile文件,添加如下行,
obj-$(CONFIG_HELLO) += hello/
當CONFIG_HELLO爲y或m時,使系統能找到hello驅動的makefile。

linux-2.6.25目錄下make menuconfig,在Device Drivers菜單下選中Hello Driver added by Dong項比如M,作爲module。然後保存配置,執行make命令,就可以看到 CC [M] drivers/hello/hello.o 的log了,hello目錄裏生成了hello.o hello.ko的等文件。

流程:
假如在make menuconfig時配置Hello Driver added by Dong爲M(即編爲模塊,而不是編進linux內核)
則.config中就會多一行CONFIG_HELLO = m
如此一來,drivers/Makefile中obj-$(CONFIG_HELLO) += hello/就變成了obj-m +=hello/
於是執行make命令時,便會進入hello目錄裏找makefile,MakeFile內容obj-$(CONFIG_HELLO) += hello.o 變成了obj-m +=hello.o,所以hello.c就被編譯成模塊了。

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