Ubuntu12.10 内核源码外编译 linux模块--编译驱动模块的基本方法
来源:互联网 发布:自学软件测试 编辑:程序博客网 时间:2024/06/07 08:39
作者:逸云沙鸥
出处:http://www.cnblogs.com/QuLory/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
1、先编写一个简单的hello模块,hello.c 源码如下:
1 #ifndef __KERNEL__ 2 # define __KERNEL__ 3 #endif 4 #ifndef MODULE 5 # define MODULE 6 #endif 7 8 // 下面的是主要的内容 9 #include <linux/kernel.h>10 #include <linux/module.h>11 #include <linux/init.h>12 13 MODULE_LICENSE("GPL");14 15 static int year=2012;16 17 int hello_init()18 {19 printk(KERN_WARNING "Hello kernel, it's %d!\n",year);20 return 0;21 }22 23 24 void hello_exit()25 {26 printk("Bye, kernel!\n");27 }28 29 // 下面两个为关键的模块函数30 module_init(hello_init);31 module_exit(hello_exit);
如果上面的代码看起来不太熟悉,那么需要查看以下相关的书籍,比如《Linux设备驱动程序,第三版》,也就是大名鼎鼎的LDD;
2、老式驱动模块编译方法:
直接写出make规则到makefile文件中,引用内核体系的头文件路径,举例如下:
1 # The path of kernel source code 2 INCLUDEDIR = /media/GoldenResources/linux/linux-2.6.30/include 3 4 # Compiler 5 CC = gcc 6 7 # Options 8 CFLAGS = -D__KERNEL__ -DMODULE -O -Wall -I$(INCLUDEDIR) 9 10 # Target11 OBJS = hello.o12 13 all: $(OBJS)14 15 $(OBJS): hello.c16 $(CC) $(CFLAGS) -c $<17 18 install:19 insmod $(OBJS)20 21 uninstall:22 rmmod hello23 24 .PHONY: clean25 clean:26 rm -f *.o
这里有我是用的一个linux内核源代码路径:/media/GoldenResources/linux/linux-2.6.30/include ,注意设置到正确的源码路径。
尝试这编译:
$makegcc -D__KERNEL__ -DMODULE -O -Wall -I/media/GoldenResources/linux/linux-2.6.30/include -c hello.cIn 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 directorycompilation terminated.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.oall : $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
开始make:
$makemake -C /lib/modules/3.5.0-17-generic/build M=/media/GoldenResources/arm/ARM高级班/内核第一天/实验代码/HelloWorld/hello modulesmake[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 directorymake[2]: *** No rule to make target `/media/GoldenResources/arm/ARM高级班/内核第一天/实验代码/HelloWorld/hello/Makefile'. Stop.make[1]: *** [_module_/media/GoldenResources/arm/ARM高级班/内核第一天/实验代码/HelloWorld/hello] Error 2make[1]: Leaving directory `/usr/src/linux-headers-3.5.0-17-generic'make: *** [all] Error 2
自动使用了当前运行中的内核,构建对应的模块,但是提示找不到Makefile,而该目录下的文件为makefile,所以尝试修改名字:
$mv makefile Makefile
特别注意,要使用Makefile才行!不能时makefile;
修改后,编译成功:
$makemake -C /lib/modules/3.5.0-17-generic/build M=/media/GoldenResources/arm/ARM高级班/内核第一天/实验代码/HelloWorld/hello modulesmake[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` modulesmake: 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/ARM高级班/内核第一天/实验代码/HelloWorld/hello/hello.komake: 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.oall : $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
作者:逸云沙鸥
出处:http://www.cnblogs.com/QuLory/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
1.Invalid module format
编译环境:PC Ubuntu 9.10(Linux-2.6.31)
比如编译2.6.31下的usbserial.ko,当insmod之后出现
insmod: error inserting 'usbserial.ko': -1 Invalid module format
dmesg后有如下信息:
usbserial: no symbol version for module_layout
网络上查找信息,说是当前编译的源码版本跟系统内核的版本没有一致。这就无法理解了,我的源码是用Ubuntu自带的新立得下的,说版本不一致很让人费解。至于相关的信息可查看:内核模块加载时的版本检查
也有些人说是编译器版本不同造成的,觉得不太可能。而且也有高人指点,明确这跟编译器无关,就是源码问题。网上找的帖子确实未能解决掉这个问题。
解决办法:使用PC自带的头文件,首先用uname -a查看自己内核版本,比如我的是:
Linux Pro 2.6.31-15-generic #50-Ubuntu SMP Tue Nov 10 14:54:29 UTC 2009 i686 GNU/Linux
于是在Makefile中将路径改为:
KERNELDIR := /usr/src/linux-headers-2.6.31-15-generic
或者KERNELDIR := /usr/src/linux-headers-$(uname -r)
再次编译,成功通过。
2.insmod时出现Unknown symbol in module
添加MODULE_LICENSE("GPL");
- Ubuntu12.10 内核源码外编译 linux模块--编译驱动模块的基本方法
- Ubuntu12.10 内核源码外编译 linux模块--编译驱动模块的基本方法
- Ubuntu12.10 内核源码外编译 linux模块--编译驱动模块的基本方法
- 内核驱动模块编译方法
- Linux内核驱动模块编译
- 自定义Linux 内核驱动模块的编译
- Linux 下面编译内核模块的 方法
- 编译内核模块的方法
- linux内核模块的编译
- Linux驱动模块编译进内核中
- Linux驱动模块编译进内核中
- Linux驱动模块编译进内核中
- linux内核驱动开发--编译外部模块
- Linux驱动模块编译进内核中
- Linux内核模块(驱动)编译详解
- 驱动模块静态编译到 Linux 内核
- Linux驱动模块编译进内核中
- Linux内核模块(驱动)编译详解
- linux 信号
- Winform----自定义控件之背景半透明遮罩加载控件
- linux 调度优先级整理
- 如何使用putty连接Ubuntu系统
- java学习day24
- Ubuntu12.10 内核源码外编译 linux模块--编译驱动模块的基本方法
- XML之SAX解析模型
- 通俗易懂JavaScript作用域(一)
- 因特尔Edison学习第1站--Edison环境搭建
- 异常:org.apache.neethi.Constants.isPolicyElement()
- EL表达式
- 横屏切换竖屏Activity的生命周期
- ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
- java.lang.RuntimeException: Invalid action class configuration that references an unknown class nam