太久没做模块化编译了,导致简单的模块编译安装都得翻书,今天趁着,需要给开发板装CH9344SER的串口驱动,做个笔记。
首先,我的开发板是定制的内核,所以想直接在开发板上编译和安装,有点麻烦,所以,我用最简单的方法,交叉编译,再移植到开发板,但是问题来,这也是我犯的第一个错误,我知道得用交叉编译器,也知道要arm格式编译,但是忘了内核版本不同!!!!!!!!
一:回到正题,先看原来官网的CH9344的Makefile
ifeq ($(KERNELRELEASE), )
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD)
clean:
rm -rf *.mk .tmp_versions Module.symvers *.mod.c *.o *.ko .*.cmd Module.markers modules.order *.a *.mod
load:
insmod ch9344.ko
unload:
rmmod ch9344
install: default
insmod ch9344.ko || true
mkdir -p /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ || true
cp -f ./ch9344.ko /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ || true
depmod -a
uninstall:
rmmod ch9344 || true
rm -rf /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ch9344.ko || true
depmod -a
else
obj-m := ch9344.o
endif
1. 判断内核环境
ifeq ($(KERNELRELEASE), )
ifeq ($(KERNELRELEASE), )
:判断变量KERNELRELEASE
是否为空。- 如果为空,说明当前不是内核构建环境(即
make
被直接调用)。
2. 定义内核路径
KERNELDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd)
KERNELDIR
:定义内核源码目录,通常是/lib/modules/<内核版本>/build
。$(shell uname -r)
获取当前系统运行的内核版本。/build
是内核源码的构建目录。
PWD
:定义当前工作目录,使用$(shell pwd)
获取。
3. 默认目标
default: $(MAKE) -C $(KERNELDIR) M=$(PWD)
default
:默认目标。$(MAKE) -C $(KERNELDIR) M=$(PWD)
:-C $(KERNELDIR)
:进入内核源码目录。M=$(PWD)
:告诉内核构建系统在PWD
(当前目录)下构建外部模块。- 这是构建内核模块的标准流程。
4. 清理目标
clean: rm -rf *.mk .tmp_versions Module.symvers *.mod.c *.o *.ko .*.cmd Module.markers modules.order *.a *.mod
clean
:清理编译生成的临时文件和目标文件。- 删除的内容包括:
- 编译生成的
.ko
(模块文件)、.o
(目标文件)、.mod.c
(模块依赖信息)。 .tmp_versions
目录(模块版本信息)、Module.symvers
(符号表)。- 其他临时文件(如
.*.cmd
、modules.order
)。
- 编译生成的
5. 加载模块
load: insmod ch9344.ko
load
:加载模块。- 使用
insmod
插入编译好的模块文件ch9344.ko
。
6. 卸载模块
unload: rmmod ch9344
unload
:卸载模块。- 使用
rmmod
卸载模块ch9344
。
7. 安装模块
install: default insmod ch9344.ko || true mkdir -p /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ || true cp -f ./ch9344.ko /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ || true depmod -a
install
:安装模块。- 首先运行
default
目标,确保模块已编译。 insmod ch9344.ko || true
:尝试加载模块,忽略错误。mkdir -p
:确保模块的目标路径存在(USB 串口驱动目录)。cp -f
:将模块文件复制到系统模块路径中。depmod -a
:更新模块依赖信息。
- 首先运行
8. 卸载模块
uninstall: rmmod ch9344 || true rm -rf /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ch9344.ko || true depmod -a
uninstall
:卸载并删除模块。rmmod ch9344 || true
:卸载模块,忽略错误。rm -rf
:删除模块文件。depmod -a
:更新模块依赖信息。
9. 内核构建环境
else obj-m := ch9344.o endif
else
:当KERNELRELEASE
不为空时,说明正在内核构建环境中。obj-m := ch9344.o
:- 定义需要构建的模块文件
ch9344.o
。 - 这是内核模块构建的标准语法。
- 定义需要构建的模块文件
到这里,应该都能大概理解这个Makefile,在做什么,假如,你的Linux环境是标准内核,可以联网更新的内核,配置好编译环境,直接make编译就可以
而我要说的是不同内核应该怎么改,以下是我自己的实例模板,自己参考修改。
# 指定 KERNELDIR,使用厂商内核路径,一般在SDK里,没有SDK的话,可以单独找内核文件就行
KERNELDIR ?= /path/to/sdk-toolchain/kernel
# 当前代码目录
PWD := $(shell pwd)
# 指定交叉编译工具链前缀,这个可以是厂商提供的SDK里的工具也可以是自己装的交叉编译
CROSS_COMPILE := /path/to/sdk-toolchain/bin/aarch64-none-linux-gnu-
# 指定目标架构
ARCH := arm64
# 编译目标
obj-m := ch9344.o
# 默认规则
default:
$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
# 清理规则
clean:
rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions modules.order Module.symvers
# 安装模块规则(可选,用于将模块复制到开发板)
install:
scp ch9344.ko user@<开发板IP地址>:/lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/
# 卸载模块规则(可选,用于从开发板卸载模块)
uninstall:
ssh user@<开发板IP地址> "rmmod ch9344; rm -f /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ch9344.ko"
最后去开发板上查看
modinfo ch9344.ko 验证
vermagic
是否与开发板内核版本一致
在开发板上加载模块:
sudo insmod /lib/modules/<开发板内核版本>/kernel/drivers/usb/serial/ch9344.ko
这就完成了,