.mod.c是什麼文件,及內核模塊Makefile模板

http://hi.baidu.com/justin_huangjh/blog/item/a211254502d73b3b87947313.html


我們可以爲代碼清單4.1的模板編寫一個簡單的Makefile:

obj-m := hello.o

並使用如下命令編譯Hello World模塊:

       make -C /usr/src/linux-2.6.15.5/ M=/driver_study/ modules

       如果當前處於模塊所在的目錄,則以下命令與上述命令同等:

         make –C /usr/src/linux-2.6.15.5 M=$(pwd) modules

       其中-C後指定的是Linux內核源代碼的目錄,而M=後指定的是hello.c和Makefile所在的目錄,編譯結果如下:

[root@localhost driver_study]# make -C /usr/src/linux-2.6.15.5/ M=/driver_study/ modules

make: Entering directory `/usr/src/linux-2.6.15.5'

CC [M] /driver_study/hello.o

/driver_study/hello.c:18:35: warning: no newline at end of file

Building modules, stage 2.

MODPOST

CC      /driver_study/hello.mod.o

LD [M] /driver_study/hello.ko

make: Leaving directory `/usr/src/linux-2.6.15.5'

從中可以看出,編譯過程中,經歷了這樣的步驟:先進入Linux內核所在的目錄,並編譯出hello.o文件,運行MODPOST會生成臨時的hello.mod.c文件,而後根據此文件編譯出hello.mod.o,之後連接hello.o和hello.mod.o文件得到模塊目標文件hello.ko,最後離開Linux內核所在的目錄。

       中間生成的hello.mod.c文件的源代碼如代碼清單4.7所示。

代碼清單4.7 模塊編譯時生成的.mod.c文件

1    #include <linux/module.h>

2    #include <linux/vermagic.h>

3    #include <linux/compiler.h>

4   

5    MODULE_INFO(vermagic, VERMAGIC_STRING);

6   

7    struct module __this_module

8    __attribute__((section(".gnu.linkonce.this_module"))) = {

9    .name = KBUILD_MODNAME,

10    .init = init_module,

11    #ifdef CONFIG_MODULE_UNLOAD

12    .exit = cleanup_module,

13    #endif

14    };

16    static const char __module_depends[]

17    __attribute_used__

18    __attribute__((section(".modinfo"))) =

19    "depends=";

hello.mod.o產生了ELF(Linux所採用的可執行/可連接的文件格式)的2個節,即modinfo和.gun.linkonce.this_module。

如果一個模塊包括多個.c文件(如file1.c、file2.c),則應該以如下方式編寫Makefile:

obj-m := modulename.o

modulename-objs := file1.o file2.o   

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

http://blog.csdn.net/zhaokugua/archive/2007/11/02/1862500.aspx

4.9模塊的編譯

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

2.4內核中,模塊的編譯只需內核源碼頭文件;需要在包含linux/modules.h之前定義MODULE;編譯、連接後生成的內核模塊後綴爲.o。

2.6內核中,模塊的編譯需要配置過的內核源碼;編譯、連接後生成的內核模塊後綴爲.ko;編譯過程首先會到內核源碼目錄下,讀取頂層的Makefile文件,然後再返回模塊源碼所在目錄。

清單2:2.4 內核模塊的Makefile模板 

#Makefile2.4
KVER=$(shell uname -r)
KDIR=/lib/modules/$(KVER)/build
OBJS=mymodule.o
CFLAGS=-D__KERNEL__ -I$(KDIR)/include -DMODULE -D__KERNEL_SYSCALLS__ -DEXPORT_SYMTAB
  -O2 -fomit-frame-pointer  -Wall  -DMODVERSIONS -include $(KDIR)/include/linux/modversions.h
all: $(OBJS)
mymodule.o: file1.o file2.o
 ld -r -o $@ $^
clean:
 rm -f *.o

在2.4 內核下,內核模塊的Makefile與普通用戶程序的Makefile在結構和語法上都相同,但是必須在CFLAGS中定義-D__KERNEL__- DMODULE,指定內核頭文件目錄-I$(KDIR)/include。有一點需注意,之所以在CFLAGS中定義變量,而不是在模塊源碼文件中定義,一方面這些預定義變量可以被模塊中所有源碼文件可見,另一方面等價於將這些預定義變量定義在源碼文件的起始位置。在模塊編譯中,對於這些全局的預定義變量,一般在CFLAGS中定義。


清單3:2.6 內核模塊的Makefile模板

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

KERNELRELEASE是在內核源碼的頂層Makefile中定義的一個變量,在第一次讀取執行此Makefile時, KERNELRELEASE沒有被定義,所以make將讀取執行else之後的內容。如果make的目標是clean,直接執行clean操作,然後結束。當make的目標爲all時,-C $(KDIR) 指明跳轉到內核源碼目錄下讀取那裏的Makefile;M=$(PWD) 表明然後返回到當前目錄繼續讀入、執行當前的Makefile。當從內核源碼目錄返回時,KERNELRELEASE已被被定義,kbuild也被啓動去解析kbuild語法的語句,make將繼續讀取else之前的內容。else之前的內容爲kbuild語法的語句, 指明模塊源碼中各文件的依賴關係,以及要生成的目標模塊名。mymodule-objs := file1.o file2.o表示mymoudule.o 由file1.o與file2.o 連接生成。obj-m := mymodule.o表示編譯連接後將生成mymodule.o模塊。

補充一點,"$(MAKE) -C $(KDIR) M=$(PWD)"與"$(MAKE) -C $(KDIR) SUBDIRS =$(PWD)"的作用是等效的,後者是較老的使用方法。推薦使用M而不是SUBDIRS,前者更明確。

通過以上比較可以看到,從Makefile編寫來看,在2.6內核下,內核模塊編譯不必定義複雜的CFLAGS,而且模塊中各文件依賴關係的表示簡潔清晰。


清單4: 可同時在2.4 與 2.6 內核下工作的Makefile

#Makefile for 2.4 & 2.6
VERS26=$(findstring 2.6,$(shell uname -r))
MAKEDIR?=$(shell pwd)
ifeq ($(VERS26),2.6)
include $(MAKEDIR)/Makefile2.6
else
include $(MAKEDIR)/Makefile2.4
endif
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章