Linux2.6 模块的两种编译方式

<

div id=”content” contentScore=”5267″>题目:内核模块的编译方法
日期:2008.5.15
作者:singyea@ 七星居

如果想要在Linux内核上扩展功能,有两条路可选,一是将自己的模块编译进Kernel,使模块成为内核的一部分;一是以模块的方式供内核加载。前者高效后者灵活,各有所长。以内核模块加载到内核是大多数设备驱动所采用的方式。关于模块的编译的方法在这里详细讨论一下。只针对2.6内核,还没看其他版本的实现方法,不知道 Linux2.6以前是不是这样的。

本人测试环境: RedHat as4 ( kernel:2.6.9-5 );
   GCC ( version 3.4.3 );
   make ( 3.80 )

将自己的模块编译进内核的详细步骤:
将自己的模块编译进内核,是写设备驱动的第一步。
首先要准备一分完整的正确的源码树,没有的可以在http://www.kernel.org 上下载,或者找到安装盘将源码包安装上。
现在假若你有了一份源码树在相应的目录。开始写自己的模块:如果你想我一样懒,那就COPY一下吧。

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3
      4
      5 static __init int test_init(void)
      6 {
      7         printk(KERN_ALERT”Test module is ready…\n”);
      8         return 0;
      9 }
     10
     11
     12 static __exit void test_exit(void)
     13 {
     14         printk(KERN_ALERT”Test module is exit …\n”);
     15         return ;
     16 }
     17
     18
     19 module_init(test_init);
     20 module_exit(test_exit);
     21
     22 MODULE_LICENSE(“Dual BSD/GPL”);
     23 MODULE_AUTHOR(“Singyea”);
     24 MODULE_DESCRIPTION(“This is a simple module”);
     25 MODULE_VERSION(“Ver 0.1”);

     保存为test.c 就是一个最简单的模块了,只有内核模块加载执行函数test_init()和模块卸载执行函数 test_exit()。还有一些关于模块的信息:
     所使用的许可声明,作者,版本,描述等,这些信息等编译成模块后可以用 modinfo 命令得到。

     将test.c copy到内核源码树中。这里的例子放到了/usr/src/kernels/2.6.9-5.EL-i686/drivers/char 下,就把它当作一个字符设备吧。呵呵
     然后修改 /usr/src/kernels/2.6.9-5.EL-i686/drivers/char下的 Kconfig 文件
     在 menu “Character devices” 下增加 一个config项,就叫 TEST吧。
     例:
menu “Character devices”
 
config TEST_MODULES
   tristate TEST
   default m
   —help—
   This is a example
   …
   …
   …
保存退出。
然后在 /usr/src/kernels/2.6.9-5.EL-i686/drivers/char下的 Makefile 文件里
增加一个对象,例:

   obj-$(CONFIG_MAGIC_SYSRQ)       += sysrq.o
   obj-$(CONFIG_ESPSERIAL)         += esp.o
   obj-$(CONFIG_TEST)              += test.o //新增加
   obj-$(CONFIG_MVME147_SCC)       += generic_serial.o vme_scc.o

这样一个新的模块就可以被内核所提供的编译系统所认识了。
进入 图形配置界面:makemenuconfig .在   
   Device Drivers —>
    Character devices —>
  
下可以看到自己所加的模块。选 M 编译成独立模块,选 * 编译进内核,空表示不进行编译。根据自己的需要对内核进行裁减
具体内容可以参照金步国的文档,N经典啊。
配置好之后就可以进行 内核及模块的编译了
make
make modules

还有一个简单的方法:

对于只想测试一个模块编写的是否正确而进行全部编译。感觉是不是太 “杀鸡用牛刀”啦 ?确实,牛人们也认识到这一点了,
就产生了另一种编译独立模块的方法。

还拿上面的例子来说 。写好之后,放在了某个文件夹下。比如在 /root/LinuxDrivers/下 这里只用编写一个 Makefile文件就可以了
在同一文件下创建如下Makefile文件:
    [root@SingyeaLinux test]# vi Makefile

    1 KERDIR ?= /usr/src/kernels/2.6.9-5.EL-i686/
    2 PWD := $(shell pwd)
    3         obj-m := test.o
    4 default:
    5         $(MAKE) -C $(KERDIR) M=$(PWD) modules

这个Makefile文件是最简单例子。其中 第一句,变量KERDIR保存的是 内核源码树的位置;第二行是取得当前路径;第三行是确定编译目标
还有一个完美点的例子,优点是它可以区分出来自己是在内核源码树里面被编译的还是在源码树之外被编译的:

 
    [root@SingyeaLinux test]# vi Makefile
    1
    2 #如果已定义KERNELRELEASE,则说明是从内核构造系统调用的,因此可利用其内建语句。
    3 ifneq($(KERNELRELEASE),)
    4         obj-m :=test.o
    5 #否则,是直接从命令行调用的,这时要调用内核构造系统
    6 else
    7 KERNELDIR ?=/usr/src/kernels/2.6.9-5.EL-i686/
    8 PWD := $(shell pwd)
    9 Default:
    10 $(MAKE) –C $(KERNELDIR) M=$(PWD) modules
    11 endif

这段代码是我从老师那里抓过来的,没改。。。

OK,一切就绪,make 一下。缯div>