1、先編寫一個簡單的hello模塊,hello.c 源碼如下:
#ifndef __KERNEL__ # define __KERNEL__ #endif #ifndef MODULE # define MODULE #endif // 下面的是主要的內容 #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> MODULE_LICENSE("GPL"); static int year=2012; int hello_init() { printk(KERN_WARNING "Hello kernel, it's %d!\n",year); return 0; } void hello_exit() { printk("Bye, kernel!\n"); } // 下面兩個為關鍵的模塊函數 module_init(hello_init); module_exit(hello_exit);
如果上面的代碼看起來不太熟悉,那么需要查看以下相關的書籍,比如《Linux設備驅動程序,第三版》,也就是大名鼎鼎的LDD;
2、老式驅動模塊編譯方法:
直接寫出make規則到makefile文件中,引用內核體系的頭文件路徑,舉例如下:
# The path of kernel source code INCLUDEDIR = /media/GoldenResources/linux/linux-2.6.30/include # Compiler CC = gcc # Options CFLAGS = -D__KERNEL__ -DMODULE -O -Wall -I$(INCLUDEDIR) # Target OBJS = hello.o all: $(OBJS) $(OBJS): hello.c $(CC) $(CFLAGS) -c $< install: insmod $(OBJS) uninstall: rmmod hello .PHONY: clean clean: rm -f *.o
這里有我是用的一個linux內核源代碼路徑:/media/GoldenResources/linux/linux-2.6.30/include ,注意設置到正確的源碼路徑。
嘗試這編譯:$make
gcc -D__KERNEL__ -DMODULE -O -Wall -I/media/GoldenResources/linux/linux-2.6.30/include -c hello.c In file included from /media/GoldenResources/linux/linux-2.6.30/include/linux/kernel.h:11:0, from hello.c:8: /media/GoldenResources/linux/linux-2.6.30/include/linux/linkage.h:5:25: fatal error: asm/linkage.h: No such file or directory compilation tterminate
make: *** [hello.o] Error 1
出現錯誤: include/linux/linkage.h:5:25: fatal error: asm/linkage.h: No such file or directory , 網上查閱相關資料后,找到不錯的說明:
請查看:http://stackoverflow.com/questions/9492559/module-compiling-asm-linkage-h-file-not-found
主要意思是這種編譯方法不能很好的解決相關的依賴體系,主要是源於歷史原因,linux內核升級很快,越來越復雜,所以建議使用kbuild體系來自動完成;故下面采用了可行的kbuild體系來完成。
3、使用kbuild進行模塊編譯:
基本方法可以參考: http://www.mjmwired.net/kernel/Documentation/kbuild/modules.txt
核心思想是,通過-C指明系統上的內核體系路徑,通過M=指明模塊源文件路徑,然后自己構造一個makefile文件,從而實現編譯過程。
3.1 構建適用於kbuild方法的makefile:
obj-m := hello.o all : $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
開始make:
$make make -C /lib/modules/3.5.0-17-generic/build M=/media/GoldenResources/arm/ARM/HelloWorld/hello modules make[1]: Entering directory `/usr/src/linux-headers-3.5.0-17-generic' scripts/Makefile.build:44: /media/GoldenResources/arm/ARM/HelloWorld/hello/Makefile: No such file or directory make[2]: *** No rule to make target `/media/GoldenResources/arm/ARM/HelloWorld/hello/Makefile'. Stop. make[1]: *** [_module_/media/GoldenResources/arm/ARM/HelloWorld/hello] Error 2 make[1]: Leaving directory `/usr/src/linux-headers-3.5.0-17-generic' make: *** [all] Error 2
自動使用了當前運行中的內核,構建對應的模塊,但是提示找不到Makefile,而該目錄下的文件為makefile,所以嘗試修改名字:
$mv makefile Makefile
特別注意,要使用Makefile才行!不能時makefile;
修改后,編譯成功:
$make make -C /lib/modules/3.5.0-17-generic/build M=/media/GoldenResources/arm/ARM/HelloWorld/hello modules make[1]: Entering directory `/usr/src/linux-headers-3.5.0-17-generic' Building modules, stage 2. MODPOST 1 modules # 說明成功編譯了一個模塊 make[1]: Leaving directory `/usr/src/linux-headers-3.5.0-17-generic'
3.2 加載和刪除內核模塊:
$sudo insmod ./hello.ko #加載 $sudo rmmod hello #刪除
並沒有看到源代碼中的輸出信息,查看系統相應日志即可:
$tail /var/log/kern.log # 注意ubuntu下的日志路徑 Oct 23 22:22:22 qunengrong-Studio-1450 kernel: [43021.773888] Hello kernel, it's 2012! Oct 23 22:22:37 qunengrong-Studio-1450 kernel: [43037.092339] Bye, kernel!
至此,我們已經可以成功編譯和加載內核模塊了;
4、額外成就,要注意模塊與內核版本的匹配:
假設我直接使用另一個內核體系進行構建,比如3.5.0-15-generic,但是當前系統運行的為3.5.0-17-generic的內核,則加載時報錯,如下:
$make -C /lib/modules/3.5.0-15-generic/build M=`pwd` modules make: Entering directory `/usr/src/linux-headers-3.5.0-15-generic' CC [M] /media/GoldenResources/arm/ARM/HelloWorld/hello/hello.o /media/GoldenResources/arm/ARM/HelloWorld/hello/hello.c:16:5: warning: function declaration isn’t a prototype /media/GoldenResources/arm/ARM/HelloWorld/hello/hello.c:23:6: warning: function declaration isn’t a prototype Building modules, stage 2. MODPOST 1 modules CC /media/GoldenResources/arm/ARM/HelloWorld/hello/hello.mod.o LD [M] /media/GoldenResources/arm/AR/HelloWorld/heARo/hello.ko make: Leaving directory `/usr/src/linux-headers-3.5.0-15-generic' $sudo insmod ./hello.ko # 版本不一致報錯 insmod: error inserting './hello.ko': -1 Invalid module format
由此可見,使用自動構建帶來的方便,將該通用Makefile分享如下:
obj-m := name.o all : $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean