Linux驅動程式開發002 Kbuild系統

2021-06-05 16:08:16 字數 3517 閱讀 1100

序言

從linux核心2.6開始,linux核心的編譯採用kbuild系統,這同過去的編譯系統有很大的不同,尤其對於linux核心模組的編譯。在新的系統下,linux編譯系統會兩次掃瞄linux的makefile:首先編譯系統會讀取linux核心頂層的makefile,然後根據讀到的內容第二次讀取kbuild的makefile來編譯linux核心。

linux核心makefile分類

kernel makefile位於linux核心源**的頂層目錄,也叫 top makefile。它主要用於指定編譯linux kernel目標檔案(vmlinux)和模組(module)。這編譯核心或模組是,這個檔案會被首先讀取,並根據讀到的內容配置編譯環境變數。對於核心或驅動開發人員來說, 這個檔案幾乎不用任何修改。

kbuild系統使用kbuild makefile來編譯核心或模組。當kernel makefile被解析完成後,kbuild會讀取相關的kbuild makefile進行核心或模組的編譯。kbuild makefile有特定的語法指定哪些編譯進核心中、哪些編譯為模組、及對應的原始檔是什麼等。核心及驅動開發人員需要編寫這個kbuild makefile檔案。

arch makefile位於arch/$(arch)/makefile,是系統對應平台的makefile。kernel top makefile會包含這個檔案來指定平台相關資訊。只有平台開發人員會關心這個檔案。

kbuild makefile

kbuild makefile的檔名不一定是

makefile

,儘管推薦使用makefile這個名字。大多的kbuild檔案的名字都是makefile。為了與其他makefile檔案相區別,你也可以指定kbuild makefile的名字為

kbuild

。而且如果「makefile」和「kbuild」檔案同時存在,則kbuild系統會使用「kbuild」檔案。

kbuild makefile的乙個最主要功能就是指定編譯什麼,這個功能是通過下面兩個物件指定的obj-?和***-objs:

obj-?指定編譯什麼,怎麼編譯?其中的「?」可能是「y」或「m」,「y」指定把物件編譯進核心中,「m」指定把物件編譯為模組。語法如下;

obj-? = $(target).o

target為編譯物件的名字。如果沒有指定***-objs,這編譯這個物件需要的原始檔就是$(target).c或$(target).s。如果指定了$(target)-objs,則編譯這個物件需要的原始檔由$(target)-objs指定,並且不能有$(target).c或$(target).s檔案。

***-objs指定了編譯物件需要的檔案,一般只有在原始檔是多個時才需要它。

只要包含了這兩行,kbuild makefile就應該可以工作了。

有時乙個物件可能嵌入到另乙個物件的目錄下,那個如何編譯子目錄下的物件呢?其實很簡單,只要指定obj_?的物件為子目錄的名字就可以了:

obj-? = $(sub_target)/

其中「?」可以是「y」或「m」,$(sub_target)是子目錄名字。

儘管在大多數情況下不需要指定編譯器選項,有時我們還是需要指定一些編譯選項的。

這些編譯選項用於指定cc、as和ld的編譯選項

編譯外部模組

有時候我們需要在核心源**數的外面編譯核心模組,編譯的基本命令是:

make -c $(kernel_dir) m=`pwd` modules

我們可以把這個命令整合到makefile裡,這樣我們就可以只輸入「make」命令就可以了。回想上一章的那個makefile,它把normal makefile 和kbuild 

makefile整合到乙個檔案中了。為了區別kbuild makefile 和normal makefile,這樣我們改寫makefile為如下形式,並且新增kbuild makefile - 「kbuild」。

##makefile

ifneq ($(kernelrelease),)

include "kbuild"

else

kernel_dir = /lib/modules/`uname -r`/build

moduledir := $(shell pwd)

.phony: modules

default: modules

modules:

make -c $(kernel_dir)  m=$(moduledir) modules

clean distclean:

rm -f *.o *.mod.c .*.*.cmd *.ko

rm -rf .tmp_versions

endif

## kbuild

module_name = helloworld

$(module_name)-objs := hello.o

obj-m 

:= $(module_name).o

一般不需要在makefile裡包含如下**,這樣寫完全是為了相容老版本的kbuild系統。kernelrelease變數在kernel makefile裡定義的,因此只有在第二次由kbuild讀取這個makefile檔案時才會解析到kbuild的內容。

ifneq ($(kernelrelease),)

include "kbuild"

else

...endif

外部標頭檔案

有時需要連線核心源**外部的系統標頭檔案,但kbuild系統預設的系統標頭檔案都在核心源**內部,如何使用外部的標頭檔案呢?這個可以借助於kbuild系統的特殊規則:

extra_cflags可以給kbuild系統新增外部系統標頭檔案,

extra_cflags += $(ext_include_path)

一般外部標頭檔案可能位於外部模組原始檔的目錄內,如何指定呢?這可以借助$(src)或$(obj)

$(src)是乙個相對路徑,它就是makefile/kbuild檔案所在的路徑。同樣$(obj)就是編譯目標儲存的路徑,預設就是源**所在路徑。

因此,我們修改kbuild檔案新增 extra_cflags 來包含外部標頭檔案儘管在這個驅動裡沒有引用外部系統標頭檔案:

## kbuild

module_name = helloworld

$(module_name)-objs := hello.o

extra_cflags := -i$(src)/include

obj-m 

:= $(module_name).o

後記

這裡我們詳細的介紹了linux核心的kbuild系統,相信你已經可以自如的寫自己的kbuild makefile了。現在開始,我們就可以寫帶有一些功能的驅動程式了。linux裡的驅動程式可以分為三類,字元裝置驅動程式,塊裝置驅動程式和網路裝置驅動程式。在後面的章節裡你會詳細的了解到這些驅動程式,同時可以了解到linux核心裡用到的一些技術,如程序管理、記憶體管理、核心同步技術、核心時鐘等。

Linux驅動程式開發 002 Kbuild系統

序言 從linux核心2.6開始,linux核心的編譯採用kbuild系統,這同過去的編譯系統有很大的不同,尤其對於linux核心模組的編譯。在新的系統下,linux編譯系統會兩 次掃瞄linux的makefile 首 先編譯系統會讀取linux核心頂層的makefile,然後根據讀到的內容第二次讀...

linux 驅動程式 高階字元驅動程式

ioctl方法 驅動程式的原型實現 int ioctl struct inode inode,struct file filp,unsigned int cmd,unsigned long arg ioctl 命令選擇 位段結構 number direction ioc read ioc write...

讀書筆記 Linux裝置驅動程式(一) 0 02

驅動程式的引數值可由in od或者modprobe在裝載模組時設定,後者還可以從配置檔案 etc modules.conf 中獲得引數賦值。這些命令能夠在命令列中接受整型和字串型賦值。如 模組需要獲得乙個叫做skull ival的整型引數和乙個叫做skull sval的字串型引數 in od sku...