直接写Makefile 文件(假设要编译的文件为hello.c)
1 ifneq ($(KERNElRELEASE),)
2 obj-m := hello.o
3 else
4 obj-m := hello.o
5 KERNELDIR ?= /lib/modules/$(shell uname -r)/build
6 PWD := $(shell pwd)
7
8 default:
9 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
10 endif
第一个ifeq ($(KERNELRELEASE),)目前,并无用处,它的由来是指在Linux源码根目录下的Makefile编译内核时,KERNELRELEASE宏会被定义,那么如果是从源码根目录开始的make则会将myhello.o模块编译进内核。
KERNELDIR ?= /usr/src/$(shell uname -r) ,这句是对KERNELDIR进行赋值,这个变量是后面我们用到的指代内核源码目录用的。
PWD := $(shell pwd),这句是对PWD变量进行赋值,作用是将$(shell pwd)的返回结果既求得当前目录的路径赋值给PWD,这个变量我们在后面指代我们要编译的驱动程序所在的位置。
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
这句是Makefile的规则:这里的$(MAKE)就相当于make,-C 选项的作用是指将当前工作目录转移到你所指定的位置。“M=”选项的作用是,当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules 命令中加入“M=dir”,程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成ko文件。
|
简单的Linux 驱动模块编译,加载过程
本文记录我的第一个Linux设备驱动程序的编译过程。遇到问题的解决方法。 环境:2.4.18-14的内核,Linux内核源码:2.4.18。 Linux内核源码路径:/usr/src/linux(这个源码是从kernel.org网站download的2.4.18版本) 按照《linux设备驱动开发详解》一书中的步骤实现经典例子"hello,world!"的例子。 具体步骤如下: ============================================= 1.源码如下: /* * hello.c -- the example of printf "hello world!" in the screen of driver program */ #include <linux/init.h> #include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");/* declare the license of the module ,it is necessary */
static int hello_init(void) { printk(KERN_ALERT "Hello World enter!\n"); return 0; }
static int hello_exit(void) { printk(KERN_ALERT "Hello world exit!\n"); }
module_init(hello_init); /* load the module */ module_exit(hello_exit); /* unload the module */
进入目录: [root@Alex_linux /]#cd /work/jiakun_test/moduletest [root@Alex_linux moduletest]# vi hello.c 然后拷入上面书上的源码。
2.编译代码: 1>.首先我在2.4内核的虚拟机上进行编译,编译过程如下: [root@Alex_linux moduletest]#gcc -D__KERNEL__ -I /usr/src/linux -DMODULE -Wall -O2 -c -o hello.o hello.c 其中-I选项指定内河源码,也就是内核源码树路径。编译结果: hello.c:1:22: net/sock.h: No such file or directory hello.c: In function `hello_init': hello.c:6: warning: implicit declaration of function `printk' hello.c:6: `KERN_ALERT' undeclared (first use in this function) hello.c:6: (Each undeclared identifier is reported only once hello.c:6: for each function it appears in.) hello.c:6: parse error before string constant hello.c: In function `hello_exit': hello.c:11: `KERN_ALERT' undeclared (first use in this function) hello.c:11: parse error before string constant hello.c: At top level: hello.c:13: warning: type defaults to `int' in declaration of `module_init' hello.c:13: warning: parameter names (without types) in function declaration hello.c:13: warning: data definition has no type or storage class hello.c:14: warning: type defaults to `int' in declaration of `module_exit' hello.c:14: warning: parameter names (without types) in function declaration hello.c:14: warning: data definition has no type or storage class 在网上查询有网友提示没有引入kernel.h 解决:vi hello.c 在第一行加入:#include <linux/kernel.h> 再次编译仍然报KERN_ALERT没有声明 修改编译条件-I,再次编译: [root@Alex_linux moduletest]#gcc -D__KERNEL__ -I /usr/src/linux -DMODULE -Wall -O2 -c -o hello.o hello.c [root@Alex_linux moduletest]#ls hello.c hello.o Makefile [root@Alex_linux moduletest]# 2>.接着我尝试在2.6内核的虚拟机上进行编译 编译过程如下: [root@JiaKun moduletest]# ls hello.c makefile [root@JiaKun moduletest]# vi hello.c [root@JiaKun moduletest]# make make -C /mylinux/kernel/2.4.18-rmk7 M=/home/alex/test/moduletest modules make: *** /mylinux/kernel/2.4.18-rmk7: No such file or directory. Stop. make: *** [modules] Error 2 [root@JiaKun moduletest]# vi makefile [root@JiaKun moduletest]# make make -C /usr/src/kernels/2.6.18-53.el5-i686 M=/home/alex/test/moduletest modules make[1]: Entering directory `/usr/src/kernels/2.6.18-53.el5-i686' scripts/Makefile.build:17: /home/alex/test/moduletest/Makefile: No such file or directory make[2]: *** No rule to make target `/home/alex/test/moduletest/Makefile'. Stop. make[1]: *** [_module_/home/alex/test/moduletest] Error 2 make[1]: Leaving directory `/usr/src/kernels/2.6.18-53.el5-i686' make: *** [modules] Error 2 [root@JiaKun moduletest]# mv makefile Makefile [root@JiaKun moduletest]# make make -C /usr/src/kernels/2.6.18-53.el5-i686 M=/home/alex/test/moduletest modules make[1]: Entering directory `/usr/src/kernels/2.6.18-53.el5-i686' CC [M] /home/alex/test/moduletest/hello.o Building modules, stage 2. MODPOST CC /home/alex/test/moduletest/hello.mod.o LD [M] /home/alex/test/moduletest/hello.ko make[1]: Leaving directory `/usr/src/kernels/2.6.18-53.el5-i686' [root@JiaKun moduletest]# ls hello.c hello.ko hello.mod.c hello.mod.o hello.o Makefile Module.symvers
3.执行代码,加载驱动模块:
2.4内核加载模块: insmod ./hello.o 但是此时并没有输出printk打印的信息。但是可以在/var/log/messages 中看到打印的信息,这是由于KERN_ALERT优先级不够高。这里 需要修改为:KERN_EMERG。再次编译,加载模块即可以看到结果 2.6内核加载模块: [root@JiaKun moduletest]# insmod hello.ko [root@JiaKun moduletest]# Message from syslogd@ at Sat Jul 26 19:52:44 2008 ... JiaKun kernel: Hello, world
有的朋友可能会出现insmod命令找不到的错误,这可能有下面几个原因: <1> 你的系统没有安装module-init-tools工具,关于此问题,只需安装即可,但是一般装完系统是有这个命令的。 <2> 环境变量没有添加导致不能使用该命令。使用echo $PATH即可查看PATH环境变量,发现没有/sbin这个路径,所以你当然不能使用insmod这个命令了。解决的方法很简单,只需在命令行输入: PATH = "$PATH:/sbin"即可添加。(insmod在/sbin这个目录下,你可以使用whereis insmod查看)。 <3> insmod这个命令需要在root权限下才能使用。 加载完成后你可以输入lsmod查看hello这个模块哦。
4.卸载驱动模块:rmmod hello.
加载模块后就可在屏幕上看到如下信息:Hello world enter. 卸载时就可在屏幕上看到如下信息:hello world exit.
[root@JiaKun moduletest]# rmmod hello.ko [root@JiaKun moduletest]# Message from syslogd@ at Sat Jul 26 19:52:58 2008 ... JiaKun kernel: Goodbye, cruel world
另外,如果有多个文件,则按下列方式编写Makefile文件(file1.c、file2.c): obj -m := modulename.o module-objs := file1.o file2.
|