Linux内核模块Makefile一个新手容易犯的错
2015-03-29 20:43
225 查看
又是受csdn bbs中一个帖子的启发,发现这个问题我之前也遇到过,所以就深入研究了一下。
以下是文件结构:
mymax.c:
Makefile:
起初我以为是printk的日志级别不对,调整到比较高的级别之后还是没有输出。
细心的朋友会看到make命令的输出结果中有一条日志:
make[2]: Circular /root/develop/kernel_module/helloworld/hello.o <- /root/develop/kernel_module/helloworld/hello.o dependency dropped.
从字面上理解就是hello.o发生了循环依赖,被dropped掉了。
然后再来看看Makefile中的确是有两个hello.o,hello-objs这行指定hello依赖两个文件hello.o和mymax.o,而hello-objs中的hello就是obj-m这一行中的hello,所以也就是说hello.o依赖于hello.o和mymax.o,从而出现了循环依赖,所以就把hello.o dropped掉了,相当于这个Makefile:
照样能编译成功,所以问题的原因找到了,那只要修改一下Makefile之后就可以了:
编译运行:
root@jusse ~/develop/kernel_module/helloworld# ls
结论:Makefile中obj-m指定的模块名和*-objs指定的依赖文件名不能相同,否则就会出现循环依赖。
至于make如何检测循环依赖,感兴趣的朋友可以看看make源码文件remake.c中的一个函数update_file_1,这个函数每更新一个文件时都会在struct file结构中打上一个updating标记,更新文件期间也会检测依赖的文件看看updating标记是否已经打过了,如果发现循环依赖(打过标记:updating==1)那就直接忽略掉那个文件了。大概就是这样,代码就不贴了。
以下是文件结构:
root@jusse ~/develop/kernel_module/helloworld# tree . ├── hello.c ├── Makefile ├── mymax.c └── mymax.h 0 directories, 4 fileshello.c:
#include <linux/init.h> #include <linux/module.h> #include "mymax.h" MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk("test1, Hello world\n"); mymax(); return 0; } static void hello_exit(void) { printk("test1, Good bye\n"); } module_init(hello_init); module_exit(hello_exit);
mymax.c:
#include <linux/init.h> #include <linux/module.h> #include "mymax.h" MODULE_LICENSE("Dual BSD/GPL"); void mymax(void) { printk("test1, enter max\n"); } EXPORT_SYMBOL(mymax);mymax.h:
#include <linux/init.h> #include <linux/module.h> void mymax(void);
Makefile:
obj-m := hello.o hello-objs := hello.o mymax.o PWD := $(shell pwd) all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: rm *.o *.ko *~ *.mod.c *.order *.symvers就是一个简单的helloworld内核模块,编译运行:
root@jusse ~/develop/kernel_module/helloworld# dmesg -c root@jusse ~/develop/kernel_module/helloworld# make make -C /lib/modules/3.13.0-36-generic/build M=/root/develop/kernel_module/helloworld modules make[1]: Entering directory `/usr/src/linux-headers-3.13.0-36-generic' make[2]: Circular /root/develop/kernel_module/helloworld/hello.o <- /root/develop/kernel_module/helloworld/hello.o dependency dropped. CC [M] /root/develop/kernel_module/helloworld/mymax.o LD [M] /root/develop/kernel_module/helloworld/hello.o Building modules, stage 2. MODPOST 1 modules CC /root/develop/kernel_module/helloworld/hello.mod.o LD [M] /root/develop/kernel_module/helloworld/hello.ko make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-36-generic' root@jusse ~/develop/kernel_module/helloworld# insmod ./hello.ko root@jusse ~/develop/kernel_module/helloworld# dmesg root@jusse ~/develop/kernel_module/helloworld#编译成功,加载模块成功,但是dmesg就是没有hello.c中用printk输出的日志,为啥?
起初我以为是printk的日志级别不对,调整到比较高的级别之后还是没有输出。
细心的朋友会看到make命令的输出结果中有一条日志:
make[2]: Circular /root/develop/kernel_module/helloworld/hello.o <- /root/develop/kernel_module/helloworld/hello.o dependency dropped.
从字面上理解就是hello.o发生了循环依赖,被dropped掉了。
然后再来看看Makefile中的确是有两个hello.o,hello-objs这行指定hello依赖两个文件hello.o和mymax.o,而hello-objs中的hello就是obj-m这一行中的hello,所以也就是说hello.o依赖于hello.o和mymax.o,从而出现了循环依赖,所以就把hello.o dropped掉了,相当于这个Makefile:
obj-m := hello.o hello-objs := mymax.o PWD := $(shell pwd) all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: rm *.o *.ko *~ *.mod.c *.order *.symvers把hello.c删除之后编译一下看看:
root@jusse ~/develop/kernel_module/helloworld# rm hello.c
root@jusse ~/develop/kernel_module/helloworld# cat Makefile
obj-m := hello.o hello-objs := mymax.o PWD := $(shell pwd) all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: rm *.o *.ko *~ *.mod.c *.order *.symvers
root@jusse ~/develop/kernel_module/helloworld# make
make -C /lib/modules/3.13.0-36-generic/build M=/root/develop/kernel_module/helloworld modules
make[1]: Entering directory `/usr/src/linux-headers-3.13.0-36-generic'
CC [M] /root/develop/kernel_module/helloworld/mymax.o
LD [M] /root/develop/kernel_module/helloworld/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /root/develop/kernel_module/helloworld/hello.mod.o
LD [M] /root/develop/kernel_module/helloworld/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-36-generic'
root@jusse ~/develop/kernel_module/helloworld# ls
hello.ko hello.mod.c hello.mod.o hello.o Makefile modules.order Module.symvers mymax.c mymax.h mymax.o
照样能编译成功,所以问题的原因找到了,那只要修改一下Makefile之后就可以了:
obj-m := world.o world-objs := hello.o mymax.o PWD := $(shell pwd) all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: rm *.o *.ko *~ *.mod.c *.order *.symvers
编译运行:
root@jusse ~/develop/kernel_module/helloworld# ls
hello.c Makefile mymax.c mymax.h从dmesg输出中可以看出成功了。
root@jusse ~/develop/kernel_module/helloworld# cat Makefile
obj-m := world.o world-objs := hello.o mymax.o PWD := $(shell pwd) all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: rm *.o *.ko *~ *.mod.c *.order *.symvers
root@jusse ~/develop/kernel_module/helloworld# make
make -C /lib/modules/3.13.0-36-generic/build M=/root/develop/kernel_module/helloworld modules
make[1]: Entering directory `/usr/src/linux-headers-3.13.0-36-generic'
CC [M] /root/develop/kernel_module/helloworld/hello.o
CC [M] /root/develop/kernel_module/helloworld/mymax.o
LD [M] /root/develop/kernel_module/helloworld/world.o
Building modules, stage 2.
MODPOST 1 modules
CC /root/develop/kernel_module/helloworld/world.mod.o
LD [M] /root/develop/kernel_module/helloworld/world.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-36-generic'
root@jusse ~/develop/kernel_module/helloworld# insmod ./world.ko
root@jusse ~/develop/kernel_module/helloworld# dmesg
[4556877.286444] test1, Hello world
[4556877.286449] test1, enter max
root@jusse ~/develop/kernel_module/helloworld#
结论:Makefile中obj-m指定的模块名和*-objs指定的依赖文件名不能相同,否则就会出现循环依赖。
至于make如何检测循环依赖,感兴趣的朋友可以看看make源码文件remake.c中的一个函数update_file_1,这个函数每更新一个文件时都会在struct file结构中打上一个updating标记,更新文件期间也会检测依赖的文件看看updating标记是否已经打过了,如果发现循环依赖(打过标记:updating==1)那就直接忽略掉那个文件了。大概就是这样,代码就不贴了。
相关文章推荐
- 关于MPU6050新手容易犯的一个小错误
- 一个维护成本低,容易修改的makefile
- 使用makefile和不使用makefile时,容易犯的一个错误。
- 新手在sae部署程序容易忽略的一个细节
- 要记住一个号码比忘记一个号码要容易的多
- [新手点滴] 关于Multilined TextBox的多行文本设置的一个小问题。
- 一个容易忽视的存储过程问题
- 使用JNDI的一个容易忽略的错误
- 一个容易忽视的Oracle安全问题
- 一个通用的Makefile
- 给新手一个很好的asp.net教程
- 一个容易忽视的Oracle安全问题
- CTDP linux 程序员手册 (4.9) 一个 makefile 脚本的例子
- (上篇二)一个从来被人忽视的软件容易失败及发展缓慢的原因
- 一个makefile文件
- 一个容易忽视的存储过程问题
- 一个容易误解的小问题:TextBox的EnableViewState为false后,为什么点击按钮PostBack,TextBox的内容还是会保持(Persist)?
- 一个简单的Makefile
- Oracle新手最常碰到的6个错误及解决方案-给一个兄弟收集的
- (上篇一)一个从来被人忽视的软件容易失败及发展缓慢的原因