编译内核模块的方法与编译一般应用程序的方法略有不同. 我们会发现在内核源码树的层层目录中, 都存在有Makefile.
即这些Makefile是分层次组织的. 以往的内核版本中, 编译模块比较麻烦, 需要我们对这些Makefile做出许多更改.
2.6的内核采用了"kbuild"编译系统, 简化了这些问题. 关于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编译模块呢?
分享到:
相关推荐
ldd3_for_linux_kernel_3.2.x
用vb做的 通讯录 是我们实训做的 是初学者需要的代码
This is the examples of the linux device driver 3 edition. everyone may download it but the author has no responsibity for what may result.
include lddbus misc-modules misc-progs pci sbull scull scullc sculld scullp scullv short shortprint skull tty usb
嵌入式驱动设备,讲述各个模块的驱动功能,以及各个模块的介绍
Linux char driver power point.
Linux Drivers development book. Covers basics of driers more simple than the stadard driver book of rubini
Linux device driver related questions and answer
linux设备驱动3(ldd3) 源码 examples 支持 linux-2.6.32.2,源码是从网上找的,自己修改后可以在linux-2.6.32.2内核环境下编译通过.注意把Makefile中的KERNELDIR ?= /home/code/buildroot/mini2440/linux-2.6.32.2改为...
Add an environment variable. Count the number of existing ones, and then allocate up a new vector of environment strings and add ours to it.
RTC in Stop mode in Kinetis MCU
Linux_设备驱动_Edition_3_-_LDD3中文版.pdf
LINUX内核驱动必看.英文版,提示英文水平
LDD3经典教程的例子源码,非常不错可供学习
LDD3学习笔记设备模型之底层实现(kobject,kset)[汇编].pdf
LDD3配套源码,配合我的百度云分享的虚拟机可以直接编译运行(虚拟机另行在我上传的资源里下载,相关可以参考我的LDD3系列博客)
ldd code ldd3驱动源代码 ldd code ldd3驱动源代码
ldd3中文版、chmldd3中文版chm
本资源为ldd3详解,该书中详细介绍了ldd3的使用以及各种驱动的设置
ldd3-examples-3.x, 在 linux 3.x 之后,端口LDD3源代码示例 ldd3-examples-3.xlinux 3 。x 之后LDD3源代码示例的端口背景LDD3是Linux设备驱动程序,第三版。 这是一本关于如何编写linux设备驱动程序的。 你可以从 ...