開(kāi)通VIP,暢享免費電子書(shū)等14項超值服
首頁(yè)
好書(shū)
留言交流
下載APP
聯(lián)系客服
2012.06.06
我們首先要進(jìn)行make,編譯成功后會(huì )生成一個(gè)globalmem.ko文件。接下來(lái)要將這個(gè)內核模塊插入到內核當中,然后還要利用mknod命令生成一個(gè)設備文件節點(diǎn)。接下來(lái)我們再利用測試程序,對我們寫(xiě)好的驅動(dòng)程序進(jìn)行測試。
那么以上的工作都可以通過(guò)下面這個(gè)Makefile文件完成,直接在shell終端輸入make就可編譯這個(gè)內核模塊,輸入make clean就可以清除一些中間文件,輸入make install就可以將編譯好的內核模塊插入到內核當中。更重要的是,這個(gè)Makefile文件具有很好的移植性。本文通過(guò)分析下面給出的Makefile文件,與大家一起更深入的學(xué)習Makefile文件的相關(guān)語(yǔ)法以及一些shell編程。
01
TARGET= globalmem
02
03
ifneq ($(KERNELRELEASE),)
04
obj-m := $(TARGET).o
05
$(TARGET)-objs := module.o global_fops.o
06
else
07
KERNEL := $(shell uname -r)
08
KDIR ?= /lib/modules/$(KERNEL)/build
09
PWD := $(shell pwd)
10
11
.PHONY all
12
.PHONY clean
13
.PHONY install
14
.PHONY
remove
15
16
all:
17
make -C $(KDIR) M=$(PWD) modules
18
clean:
19
make -C $(KDIR) M=$(PWD) clean
20
install:
21
@sudo ./$(TARGET).sh
22
:
23
@sudo ./clean.sh
24
endif
這個(gè)Makefile文件(新Makefile)比這里的Makefile文件(舊Makefile)強大了很多。
1.條件語(yǔ)句
首先注意這個(gè)新的Makefile文件在邏輯結構上發(fā)生了很大的變化,采用了條件語(yǔ)句:ifneq-else-endif。這個(gè)條件語(yǔ)句是用來(lái)判斷括號中逗號前后的兩個(gè)變量是否不相等。ifneq之后為符合條件時(shí)所要執行的語(yǔ)句,相應的else之后為不符合條件時(shí)要執行的語(yǔ)句。上述Makefile文件中的ifneq ($(KERNELRELEASE),)是用來(lái)判斷KERNELRELEASE變量是否為空,不為空則符合條件。
類(lèi)似的還有下面的條件語(yǔ)句,只不過(guò)條件判斷的類(lèi)型不同。
ifeq-else-endif:如果兩個(gè)變量相等,則滿(mǎn)足條件。
下面兩種條件語(yǔ)句中,條件判斷處為變量名,是用來(lái)判斷此變量是否被定義過(guò)。
ifdef-else-endif:如果變量被定義,滿(mǎn)足條件。
ifndef-else-endif:如果變量未被定義,滿(mǎn)足條件。
不過(guò),上述兩個(gè)條件語(yǔ)句所判斷的變量定義沒(méi)有遞歸性,比如下面例子:
1
path=
2
cur_path=$(path)
3
ifdef cur_path
4
right=yes
5
6
right=no
7
這個(gè)例子中最終執行的是right=yes。雖然path為空,但是cur_path=$(path)卻被認為是定義了cur_path變量。正如上面所說(shuō)定義沒(méi)有遞歸行。
2.變量賦值
在Makefile文件中定義一個(gè)變量的格式為:變量名 賦值符 變量值
賦值符通常有以下四種類(lèi)型:=,:=,?=,+=。對于賦值符=與我們平日里使用的等號差不多,但是這里我們需要清除一個(gè)概念,那就是遞歸展開(kāi)變量。為了更清除的說(shuō)明上面的概念,請看下面的例子:
first=$(second)
second=$(third)
third=yes
echo $(first)
很顯然結果為yes。當執行make時(shí),first首先展開(kāi)為second,接著(zhù)second又展開(kāi)成為third,再后來(lái)引用third的值即yes??梢钥吹絝irst是遞歸展開(kāi)而得到最后的yes值的。這便是我們剛才所謂的遞歸展開(kāi)變量。
而與上述變量賦值符號不同的是,:=賦值符號是立即展開(kāi)變量的,同樣的例子,只不過(guò)這次我們使用:=賦值符:
first:=$(second)
second:=$(third)
third:=yes
此時(shí)first為空。這是因為在定義first變量時(shí)就立即展開(kāi)了second,因為second此時(shí)未定義。即便此句之后為second變量賦了值,但first的值為空。
另外兩個(gè)賦值符號比較容易理解。首先+=賦值符是在變量原有值的基礎上再增加新的值,而不是覆蓋原有變量值。而?=賦值符首先會(huì )判斷變量實(shí)現是否已經(jīng)被賦值,只有之前未被賦值的變量此刻才能被賦值。
OK,了解了賦值符號的含義,那么再次看上述的Makefile文件,就會(huì )清晰很多。
3.偽目標
正如上述所言,直接在shell終端輸入make就會(huì )執行目標all后的命令,這并不是all目標具有什么默認的效果。只不過(guò)在Makefile文件中,第一個(gè)目標總被認為是最終目標。因此可以想象到,當你交換一下all和clean的位置,直接執行make時(shí)會(huì )自動(dòng)執行clean后面的命令。并且不一定總對第一個(gè)目標起名為all,你可以使用你喜歡的目標名(也許all是一種無(wú)聲的約定
通常在clean這樣的目標后都沒(méi)有依賴(lài)文件,因為我們的目的是想讓make執行這些目標后的命令。但是當Makefile文件所在目錄下有一個(gè)名為clean的文件時(shí),此時(shí)make clean就會(huì )被認為是生成clean目標文件。而clean后是沒(méi)有任何依賴(lài)文件的,所以每次make clean后clean目標文件都會(huì )被認為是最新,而不去執行下面的命令,這雖然符合語(yǔ)法規則,但并不能達到我們使用clean的目的。
因此我們必須將clean這種目標定義成偽目標。定義方法為:.PHONY:all。這樣不管該目錄下是否有同名的文件都會(huì )執行clean后的命令?,F在你應該明被為什么MAKEFILE文件中有這么多以.PHONY開(kāi)頭的目標文件了吧。
4.為什么要用makefile
內核模塊化簡(jiǎn)單實(shí)用,但是編譯卻成了問(wèn)題:有時(shí)候我們只是改動(dòng)了某個(gè)文件的一小部分就不得不編譯整個(gè)內核,這是個(gè)很可怕的事情。但是GNU make引入后,這個(gè)問(wèn)題就迎刃而解了:make只會(huì )編譯已被改動(dòng)代碼的文件,而不是將所有文件都編譯。但是make具體如何對源文件進(jìn)行編譯,怎么編譯?這個(gè)時(shí)候就需要makefile文件了。在之前的文章當中,我們對Makefile文件下過(guò)“編譯規則”這樣的定義,下面通過(guò)分析上面的Makefile文件,我們具體感受一下這個(gè)“編譯規則”。
整個(gè)Makefile文件根據KERNELRELEASE的值來(lái)劃分不同的編譯規則(方式),這里的KERNELRELEASE只會(huì )在內核源碼目錄下顯示當前內核的版本號。
一般情況下,我們編寫(xiě)的內核模塊源文件所在的目錄并非位于內核源碼根目錄(或其子目錄)下。那么此時(shí)就不符合ifueq條件,即執行else語(yǔ)句下的編譯規則。這種情況下,當我們輸入make后,就會(huì )執行make -C $(KDIR) M=$(PWD) modules這條命令。注意這條命令后的modules,它表示將會(huì )編譯所有在配置菜單中被選作模塊編譯的那些內容(也就是賦值給obj-m的那些目標)。接下來(lái)由于-C $(KDIR)參數的原因,make會(huì )轉向內核源碼根目錄下去執行。根據M后的目錄,編譯我們寫(xiě)的內核模塊源碼,生成.o文件。接著(zhù)聯(lián)合一些中間文件生成.ko文件。這便是make生成整個(gè)內核目標文件的過(guò)程。這個(gè)過(guò)程可以在make之后在終端產(chǎn)生的一系列描述文字得到。
上面這種情況會(huì )將我們編寫(xiě)的內核模塊源碼編譯成內核模塊目標文件,接下來(lái)就是我們熟悉的內核模塊插入了。不過(guò)當我們所寫(xiě)的內核模塊文件處于內核源碼目錄下時(shí),KERNELRELEASE就會(huì )非空(此時(shí)為版本號),那么此時(shí)就滿(mǎn)足ifueq條件了。什么時(shí)候我們編寫(xiě)的內核模塊源碼會(huì )處在內核源碼目錄下?此時(shí)的內核編譯是那種方式?
在前面的文章中我們假設已經(jīng)寫(xiě)好了驅動(dòng)代碼,然后在Kconfig文件中為這個(gè)驅動(dòng)編寫(xiě)配置選項。在配置菜單中有了此驅動(dòng)的相關(guān)配置選項后,接下來(lái)用戶(hù)可以選擇是否會(huì )將此驅動(dòng)源碼一起編譯進(jìn)內核。那么此時(shí)Makefile文件的作用就是將此內核模塊源碼編譯進(jìn)內核(obj-m := $(TARGET).o)。不過(guò)注意,只是通知內核下次編譯“帶上我”,并沒(méi)有實(shí)際編譯。
現在應該明白整個(gè)Makefile文件的邏輯結構了吧?
微信登錄中...請勿關(guān)閉此頁(yè)面