
接上一篇从零看懂驱动框架 设备分类 最简模板上一篇我们拿到了最简内核驱动.c源码但是内核驱动不能用gcc直接编译必须借助内核源码树进行编译。本篇讲解驱动专用Makefile语法、编译步骤、insmod/rmmod/lsmod/modinfo/modprobe全套命令新手照着敲即可跑通实验。一、为什么驱动不能直接 gcc xxx.c普通应用程序链接glibc用户态库gcc直接编译。内核驱动运行在内核空间要调用内核导出的函数、头文件必须使用内核本身的编译体系不能链接用户态C库。重点编译驱动必须要有对应版本的内核源码/内核头文件内核版本必须和运行开发板/虚拟机的内核版本严格匹配否则会出现版本魔数校验失败模块加载报错。二、驱动专用Makefile完整模板新建文件名字就叫Makefile注意大小写M大写不要后缀和驱动c文件放在同一个目录。假设驱动源码文件名叫mydrv.c# 判断是否传入KERNELDIR没有就使用本机内核路径 KERNELDIR ? /lib/modules/$(shell uname -r)/build # 当前源码所在目录 PWD : $(shell pwd) # 要编译生成的模块名对应 mydrv.c → mydrv.ko obj-m mydrv.o # make的默认目标 all: make -C $(KERNELDIR) M$(PWD) modules # make clean 清理编译产物 clean: make -C $(KERNELDIR) M$(PWD) cleanMakefile逐行小白讲解KERNELDIR ? /lib/modules/$(shell uname -r)/build?如果变量没有被外部赋值才赋值交叉编译的时候可以外部传入指定内核路径覆盖。$(shell uname -r)shell命令获取当前正在运行的内核版本号。/lib/modules/xxx/buildUbuntu虚拟机本地编译指向内核头文件软链接做开发板交叉编译时这里改成开发板内核源码绝对路径。PWD : $(shell pwd):立即赋值获取当前源码文件夹路径。obj-m mydrv.o核心驱动Makefile最关键一行obj‑m表示把这个文件编译成可动态加载的内核模块.koobj‑y编译进内核镜像zImage开机就内置不能rmmod卸载。mydrv.o对应源码mydrv.c会自动生成mydrv.ko不要写komake -C $(KERNELDIR) M$(PWD) modules-C $(KERNELDIR)切换工作目录到内核源码目录执行内核顶层MakefileM$(PWD)告诉内核编译系统外部模块源码在当前PWD目录modules内核Makefile目标专门编译外部内核模块clean清理编译出来的.ko、.o、.mod.c等中间文件。✅编译操作终端进入源码目录执行make编译成功后目录生成mydrv.ko就是我们的内核模块文件。⚠️交叉编译小提示开发板场景# 示例传入交叉编译器开发板内核路径makeKERNELDIR/home/xxx/linux-5.4ARCHarmCROSS_COMPILEarm-linux-gnueabihf-编译产物说明*.ko真正内核模块拷贝到开发板使用*.mod.c内核自动生成中间文件*.o编译目标文件modules.order、Module.symvers模块符号表多个模块依赖时需要三、内核模块全套操作命令必考实操注意大部分模块加载卸载操作需要root权限Ubuntu加sudo开发板一般默认root。1. lsmod 列出当前已经加载的内核模块lsmod作用查看系统哪些ko已经载入内核第一列模块名第二列占用内存第三列被哪些其他模块依赖。2. insmod 手动加载模块sudoinsmod mydrv.ko直接指定ko文件路径加载。缺点不会自动解决模块依赖如果本模块依赖别的模块insmod会报错。查看打印输出驱动里面printk打印用dmesg看dmesg# 实时追踪打印dmesg-wprintk不会直接输出终端存在内核环形缓冲区要用dmesg查看日志。3. modprobe 智能加载模块sudomodprobe mydrv不需要写.ko后缀只写模块名字会自动查找模块路径自动加载依赖的其他模块前提条件ko需要拷贝到系统模块目录/lib/modules/$(uname -r)/执行depmod更新模块依赖数据库modprobe才能识别。简单理解insmod简单粗暴modprobe智能处理依赖。4. rmmod 卸载模块sudormmod mydrv只写模块名字不要加.ko后缀执行驱动的__exit退出函数。注意模块正在被程序占用的时候rmmod会失败。5. modinfo 查看模块信息modinfo mydrv.ko读取ko内部信息作者、协议、描述、模块参数、版本就是我们代码里MODULE_LICENSE、MODULE_AUTHOR这些宏生成的信息。6. depmod 更新模块依赖数据库配合modprobe使用sudodepmod把新拷贝的ko注册进系统模块列表modprobe才能找到这个模块。完整实操流程示例虚拟机#1 编译make#2 加载模块sudoinsmod mydrv.ko#3 看内核打印dmesg#4 查看已加载模块lsmod#5 查看模块信息modinfo mydrv.ko#6 卸载模块sudormmod mydrv#7 清理编译产物makeclean四、常见踩坑点小白高频报错版本魔数不匹配version magic does not match原因编译用的内核头文件版本 和 运行内核版本不一致。虚拟机不要随便升级内核开发板编译驱动必须使用和烧录内核一模一样的源码。MODULE_LICENSE(GPL)忘记写dmesg里面出现tainted kernel内核污染警告部分内核函数调用直接失败。必须写GPL。make报错找不到内核头文件Ubuntu安装内核头文件sudoaptinstalllinux-headers-$(uname-r)rmmod提示module is in use模块正在被使用有应用程序打开设备要先关闭应用再卸载。modprobe找不到模块ko没有放到系统模块目录没有执行depmod改用insmod指定ko完整路径临时测试。五、本篇知识点总结驱动不能gcc直接编译依靠内核Makefile编译体系obj‑m xxx.o编译生成ko模块。Makefile关键参数‑C切换内核目录M指定外部模块源码目录。命令速记|命令|功能|| ---- | ---- ||lsmod|列出已加载内核模块||insmod xxx.ko|直接加载ko不处理依赖||modprobe xxx|智能加载自动处理依赖||rmmod xxx|卸载模块不加ko后缀||modinfo xxx.ko|查看模块元信息||dmesg|查看printk内核打印||make clean|清理驱动编译产物|本篇为专栏入门免费章节完整专栏包含三大基础驱动设备面向入门、内核机制原理讲解面向面试、多套驱动框架配套源码面向工作等内容后续进阶内容仅专栏订阅用户可见点击专栏主页订阅解锁全部教程。