今天看着《Linux设备驱动程序》,跟着编写一个简单的hello模块:
hello.c
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_INFO "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_INFO "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefile:(取自 https://www.cnblogs.com/mrzhangxinjie/p/7170736.html)
obj-m :=hello.o //目标文件
#module-objs := file1.o file.o //当模块有多个文件组成时,添加本句
KDIR :=/usr/src/linux //内核路径,根据实际情况换成自己的内核路径,嵌入式的换成嵌入式,PC机的指定PC机路径
PWD := $(shell pwd) //模块源文件路径
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
@rm -rf *.mod.*
@rm -rf .*.cmd
@rm -rf *.o
@rm -rf Module.*
clean:
rm -rf *.ko
结果make编译出现错误;
Makefile:7: *** commands commence before first target。 停止。
Makefile:7: *** 遗漏分隔符 。 停止。
查找原因,发现是因为复制的原因, 第一个错误是make行开头不是tab,第二个错误是其他行开头不是tab,改成tab后:
obj-m :=hello.o //目标文件
#module-objs := file1.o file.o //当模块有多个文件组成时,添加本句
KDIR :=/usr/src/linux //内核路径,根据实际情况换成自己的内核路径,嵌入式的换成嵌入式,PC机的指定PC机路径
PWD := $(shell pwd) //模块源文件路径
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
@rm -rf *.mod.*
@rm -rf .*.cmd
@rm -rf *.o
@rm -rf Module.*
clean:
rm -rf *.ko
再次make,依然有错误:
make -C /usr/src/linux //内核路径,根据实际情况换成自己的内核路径,嵌入式的换成嵌入式,PC机的指定PC机路径 SUBDIRS=/home/zhangjian/huangzhe/linux_drive/misc-modules //模块源文件路径 modules
make: *** /usr/src/linux: 没有那个文件或目录。 停止。
make: *** [all] 错误 2
原来是没有更改内核路径(参考https://www.jianshu.com/p/62eff1275b77):
obj-m :=hello.o //目标文件
#module-objs := file1.o file.o //当模块有多个文件组成时,添加本句
KDIR :=/lib/modules/`uname -r`/build //内核路径,根据实际情况换成自己的内核路径,嵌入式的换成嵌入式,PC机的指定PC机路径
PWD := $(shell pwd) //模块源文件路径
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
@rm -rf *.mod.*
@rm -rf .*.cmd
@rm -rf *.o
@rm -rf Module.*
clean:
rm -rf *.ko
再次make,仍有问题,继续查找原因,发现注释符不对,shell中应该用#:
obj-m :=hello.o #目标文件
#module-objs := file1.o file.o #当模块有多个文件组成时,添加本句
KDIR :=/lib/modules/`uname -r`/build #内核路径,根据实际情况换成自己的内核路径,嵌入式的换成嵌入式,PC机的指定PC机路径
PWD := $(shell pwd) #模块源文件路径
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
@rm -rf *.mod.*
@rm -rf .*.cmd
@rm -rf *.o
@rm -rf Module.*
clean:
rm -rf *.ko
再次make,成功编译出hello.ko模块!
VirtualBox:~/linux_drive/misc-modules$ ls
complete.c hello.ko jit.c Makefile modules.order sleepy.c
faulty.c hellop.c kdataalign.c Makefile1 seq.c
hello.c jiq.c kdatasize.c Makefile (复件) silly.c
执行 sudo insmod hello.ko 安装hello模块:
sudo insmod hello.ko
执行lsmod命令查看模块是否安装成功:
VirtualBox:~/linux_drive/misc-modules$ lsmod
Module Size Used by
hello 16384 0
nls_utf8 16384 1
isofs 40960 1
vboxsf 40960 1
执行 sudo rmsmod hello 卸载hello模块:
sudo rmmod hello
再次执行lsmod命令查看模块是否卸载成功:
VirtualBox:~/linux_drive/misc-modules$ lsmod
Module Size Used by
nls_utf8 16384 1
isofs 40960 1
vboxsf 40960 1
bnep 20480 2
在安装卸载模块期间,发现没有打印信息,查阅资料(https://blog.csdn.net/FallingU/article/details/76166194)
查看内核打印信息需要用到dmesg命令:
VirtualBox:~/linux_drive/misc-modules$ dmesg
/太多,省略/
[ 6162.325693] Hello, world
[ 6164.141443] Goodbye, cruel world
模块的编译有两种形式,一种是编译成模块,即上面的obj-m
,另一中是直接编译到内核文件中,则上面的obj-m
需要更改为obj-y(
https://www.jianshu.com/p/62eff1275b77)