Linux 內核模塊編譯 Makefile 解析

一、模塊的編譯

       我們在前面內核編譯中驅動移植那塊,講到驅動編譯分爲靜態編譯動態編譯靜態編譯即爲將驅動直接編譯進內核,動態編譯即爲將驅動編譯成模塊。

而動態編譯又分爲兩種:

a -- 內部編譯

       在內核源碼目錄內編譯

b -- 外部編譯

       在內核源碼的目錄外編譯

 

二、具體編譯過程分析   

        注:本次編譯是外部編譯,使用的內核源碼是Ubuntu 的源代碼,而非開發板所用linux 3.14內核源碼,運行平臺爲X86

        對於一個普通的linux設備驅動模塊,以下是一個經典的makefile代碼,使用下面這個makefile可以完成大部分驅動的編譯,使用時只需要修改一下要編譯生成的驅動名稱即可。只需修改obj-m的值。

ifneq  ($(KERNELRELEASE),)
obj-m:=hello.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
all:
    make -C $(KDIR) M=$(PWD) modules
clean:
    rm -f *.ko *.o *.symvers *.cmd *.cmd.o
endif

1、makefile 中的變量

    先說明以下makefile中一些變量意義:

(1)KERNELRELEASE           在linux內核源代碼中的頂層makefile中有定義

(2)shell pwd                             取得當前工作路徑

(3)shell uname -r                    取得當前內核的版本號

(4)KDIR                                     當前內核的源代碼目錄。

關於linux源碼的目錄有兩個,分別爲

 "/lib/modules/$(shell uname -r)/build"

"/usr/src/linux-header-$(shell uname -r)/"

       但如果編譯過內核就會知道,usr目錄下那個源代碼一般是我們自己下載後解壓的,而lib目錄下的則是在編譯時自動copy過去的,兩者的文件結構完全一樣,因此有時也將內核源碼目錄設置成/usr/src/linux-header-$(shell uname -r)/。關於內核源碼目錄可以根據自己的存放位置進行修改。

(5)make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules

這就是編譯模塊了:

a -- 首先改變目錄到-C選項指定的位置(即內核源代碼目錄,其中保存有內核的頂層makefile;

b -- M=選項讓該makefile在構造modules目標之前返回到模塊源代碼目錄;然後,modueles目標指向obj-m變量中設定的模塊;在上面的例子中,我們將該變量設置成了hello.o。

 

2、make 的的執行步驟

a -- 第一次進來的時候,宏“KERNELRELEASE”未定義,因此進入 else;

b -- 記錄內核路徑,記錄當前路徑;

       由於make 後面沒有目標,所以make會在Makefile中的第一個不是以.開頭的目標作爲默認的目標執行。默認執行all這個規則

c -- make -C $(KDIR) M=$(PWD) modules

    -C 進入到內核的目錄執行Makefile ,在執行的時候KERNELRELEASE就會被賦值,M=$(PWD)表示返回當前目錄,再次執行makefile,modules 編譯成模塊的意思

     所以這裏實際運行的是

     make -C /lib/modules/2.6.13-study/build M=/home/fs/code/1/module/hello/ modules

d -- 再次執行該makefile,KERNELRELEASE就有值了,就會執行obj-m:=hello.o

     obj-m:表示把hello.o 和其他的目標文件鏈接成hello.ko模塊文件,編譯的時候還要先把hello.c編譯成hello.o文件

 

可以看出make在這裏一共調用了3次

   1)-- make
   2)-- linux內核源碼樹的頂層makedile調用,產生。o文件
   3)-- linux內核源碼樹makefile調用,把.o文件鏈接成ko文件

 

3、編譯多文件

若有多個源文件,則採用如下方法:

obj-m := hello.o

hello-objs := file1.o file2.o file3.o

 

三、內部編譯簡單說明

        如果把hello模塊移動到內核源代碼中。例如放到/usr/src/linux/driver/中, KERNELRELEASE就有定義了。

     在/usr/src/linux/Makefile中有KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)$(LOCALVERSION)。

這時候,hello模塊也不再是單獨用make編譯,而是在內核中用make modules進行編譯,此時驅動模塊便和內核編譯在一起。

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