又是受csdn bbs中一个帖子的启发,发现这个问题我之前也遇到过,所以就深入研究了一下。
以下是文件结构:
root@jusse ~/develop/kernel_module/helloworld# tree
.
├── hello.c
├── Makefile
├── mymax.c
└── mymax.h
0 directories, 4 files
hello.c:
#include
#include
#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
#include
#include "mymax.h"
MODULE_LICENSE("Dual BSD/GPL");
void mymax(void)
{
printk("test1, enter max\n");
}
EXPORT_SYMBOL(mymax);
mymax.h:
#include
#include
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
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#
从dmesg输出中可以看出成功了。
结论:Makefile中obj-m指定的模块名和*-objs指定的依赖文件名不能相同,否则就会出现循环依赖。
至于make如何检测循环依赖,感兴趣的朋友可以看看make源码文件remake.c中的一个函数update_file_1,这个函数每更新一个文件时都会在struct file结构中打上一个updating标记,更新文件期间也会检测依赖的文件看看updating标记是否已经打过了,如果发现循环依赖(打过标记:updating==1)那就直接忽略掉那个文件了。大概就是这样,代码就不贴了。