关于kbuild, 可参考内核源码树中的 /Documentation/kbuild/modules.txt.
编译之前, 肯定是需要源文件的. 这些源文件可以放在内核源码树中, 也可以放在内核源码树之外的任何地方. 根据源文件存在的目录, 存在两种编译方法: 在源码树之中和在源码树之外.
    
     在源码树中编译模块
    
    
官方内核模块的源代码都是按模块(驱动)类型组织的, 我们到内核源码树的drivers目录可以看到char, usb, block之类的子目录. 那么我们在内核源码树中添加文件时, 最好也遵循这些分类. 分类的规则自己灵活把握.
下面以前面的”hello, world”这个简单的模块为例, 来看看如何在内核源码树中编译模块.
    
     1, 不新建子目录
    
    
    (1) 先在内核源码树中的drivers目录编辑一个c源程序, 名为hello.c.
    
    (2) 修改drivers目录的Makefile文件, 添加: obj-m += hello.o
    
    (3) 重新编译内核(回到源码树根目录, 运行 $
    
     sudo make
    
    ).
这样, 在drivers目录多出了这样几个文件: hello.mod.c, hello.mod.o, hello.o, hello.ko. hello.ko就是编译出来的模块了.
    
     2, 新建子目录
    
    
    如果源文件比较多, 可以在drivers目录中新建子目录. 还是以hello, world为例:
    
    (1) 在内核源码树的drivers目录中新建一个hello子目录, 并将hello.c放在hello目录中.
    
    (2) 修改drivers目录的Makefile文件, 添加: obj-m += hello/
    
    (3) 在hello目录中新建一个Makefile文件, 内容为: obj-m += hello.o
    
    (4) 重新编译内核(回到源码树根目录, 运行 $
    
     sudo make
    
    ).
这样, 新生成的模块文件就位于hello目录中.
| 若在内核源码树中编译模块, 如果不新建子目录, 那么只需修改当前目录的Makefile, 否则应该在当前新建的子目录中新建Makefile指定编译选项, 并修改上层目录的Makefile以让kbuild能够进入新建的子目录. | 
    
     在源码树之外编译模块
    
    
还是以上面的hello, world为例. 在当前目录有个hello.c:
    (1)首先在模块代码所在的目录新建一个Makefile, 内容为:
    
    obj-m := hello.o
    
    (2)这样调用make命令:
    
    $
    
     sudo make -C /usr/local/src/kernel/linux-2.6.16.20 SUBDIRS=$PWD modules
    
    
    这里/usr/local/src/kernel/linux-2.6.16.20是内核源码树所在的目录.
-C表示要求make先切换到-C指定的目录. SUBDIRS(也可以用M代替SUBDIRS)使make在编译模块之前回到当前目录.
整个编译过程实际上是执行-C指定的内核源码树的Makefile, 并通过SUBDIR指定你要编译的内核源文件的目录.
    
     简化命令行输入
    
    
    每次调用make的时候输入这些参数比较比较麻烦, 可以这样来改写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
    这样, 只需在当前目录调用 $
    
     sudo make
    
    就可以完成上面的工作. 调用 $
    
     sudo make clean
    
    将删除所有新生成的文件.
    上面的Makefile是这样确定内核源码树所在的目录的: 我们先到/lib/modules目录, 会看到一些以内核版本为名的目录, 目录中有一个build文件, 它是一个符号连接, 指向内核源码树. 那么如何确定进入哪个内核版本的目录呢? 这就可以通过 $
    
     uname -r
    
    来确定, 它指出了当前运行内核的版本.
    还可以进一步简化这个Makefile:
    
    
     obj-m := hello.o
    
    
    
    
     KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    
    
    
     PWD := $(shell pwd)
    
    
    
    
     default:
    
    
    
     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    
    
    
     clean:
    
    
    
     $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
    
这样不用在Makefile中一次又一次地指定内核代码树的目录.
| 上面的例子中只讨论了所有的代码在一个文件中的情况. 若代码分布在多个源文件中,  比如file1.c, file2.c, 生成hello.ko. 应该这样写Makefile: obj-m := hello.o hello-objs := file1.o file2.o 注意, 虽然我们的目的是生成.ko文件, 但在Makefile中写为.o! | 
    
     为预编译的内核编译模块
    
    
前面都讨论的是针对当前运行的内核编译模块, 实际上, 也可以针对非当前运行的内核编译模块.比如, 我当前运行的内核版本是2.6.16, 但系统中还有2.6.12版的内核. 在不想重启来运行2.6.12版内核的情况下, 如何针对2.6.12编译模块呢?
转载于:https://www.cnblogs.com/wangtianxj/archive/2009/05/05/1449991.html
 
