Linux Dkms驱动设计使用
DKMS简介
1. 什么是DKMS
这是一个在Linux操作系统中广泛使用的程序/框架,用于简化不在内核源码树中的第三方模块的构建和维护。
核心价值:解决“内核升级”的兼容性痛点
在Linux系统中,当内核版本升级时,之前安装的第三方内核模块(如显卡驱动)很可能因接口变化而无法使用,需要重新编译安装。DKMS的核心价值正是在于自动化地解决这个问题。
它的主要工作方式是:当系统安装了一个新内核后,DKMS框架会自动触发,为这个新内核重新构建并安装它所管理的所有模块。这免去了用户等待模块开发者发布新版本或手动重新编译的麻烦
2. 工作原理
- 工作方式
DKMS在内核源码树之外维护一个独立的目录树,用于存放模块的源代码和已编译的二进制文件。这种设计将模块与特定内核版本解耦。 - 与包管理器集成
现代Linux发行版(如Arch Linux、Ubuntu等)的包管理器常通过钩子(hooks)与DKMS深度集成,使得在系统升级时,模块的重建工作能在后台无缝自动完成。 - 版本管理
支持多内核、多驱动版本共存,可单独移除某内核下的驱动,不影响其他内核。
配置方法
1. 环境准备
Centos系和国产linux操作系统官方源中不包含 DKMS 软件包,需要启用并安装 EPEL (Extra Packages for Enterprise Linux) 仓库。
# redhat/centos
sudo yum install -y epel-release
sudo yum install -y dkms
# ubuntu/debian
sudo apt install dkms
2. 源码托管
将驱动源码统一放置 /usr/src/-/,目录内置 dkms.conf 配置文件,记录编译参数、依赖、模块名称、内核适配规则。
# 定义模块名和版本,必须与目录名 /usr/src/hello_world-1.0 一致
PACKAGE_NAME="hello_world"
PACKAGE_VERSION="1.0"
# 支持自定义参数,例如:
# CUSTOM_PARAM1="value1"
# CUSTOM_PARAM2="value2"
# ...
PACKAGE_DEST="/opt/hello_world"
# 目标模块名列表,索引从0开始
BUILT_MODULE_NAME[0]="hello_world"
# 目标模块安装目录列表,索引从0开始,常用linux发行版本忽略此字段
DEST_MODULE_LOCATION[0]="/updates"
# 开启内核更新时的自动重编译,可选值:yes/no
AUTOINSTALL="yes"
# 编译和安装前后执行的脚本,可选
# 脚本中使用的参数必须从DKMS中作为参数传入,例如 $PACKAGE_DEST, $PACKAGE_NAME 等
PRE_BUILD="./pre_build.sh $PACKAGE_DEST"
# 低版本DKMS不支持POST_BUILD
POST_BUILD="./post_build.sh"
PRE_INSTALL="./pre_install.sh"
POST_INSTALL="./post_install.sh"
# 编译清理指令,也可以使用脚本
# MAKE="./build.sh"
MAKE="make all"
CLEAN="make clean"
3. 模块注册
执行 dkms add 将源码注册进 DKMS 数据库,系统记录该驱动存在。
# 兼容dkms2/3
dkms add -m <module> -v <version>
# 高版本语法
dkms add <module>-<version>
4. 编译构建
手动:dkms build 针对指定内核编译 .ko 驱动
自动:系统更新内核包(linux-image/linux-headers)后,DKMS 钩子脚本自动遍历已注册模块,匹配新内核头文件完成编译。
# 兼容dkms2/3
dkms build -m <module> -v <version>
# 自动注册,覆盖旧版本,低版本不可用
dkms build <module>-<version> --force
5. 安装部署
编译完成后 dkms install 将 .ko 放入 /lib/modules/<内核版本>/XXX/ 标准驱动目录。
# 兼容dkms2/3
dkms install -m <module> -v <version>
# 自动注册,覆盖旧版本,低版本不可用
dkms install <module>-<version> --force
业务分离
实际开发过程中由于项目代码无法开源,因此需要将内核ABI层代码与业务代码分离,将内核ABI层代码注册到DKMS,业务代码则在用户空间实现。
若业务代码无法完全剥离,则可用考虑将业务代码编译为二进制链接文件。
假设项目代码结构如下:
- hello_world-1.0/
- dkms/
- obj/
- hello_world.o
- main.c
- dkms.conf
- Makefile
- obj/
- hello_world.c
- hello_world.h
- Makefile
- dkms/
主目录代码编译生成 hello_world.o,随内核代码注册到 DKMS;DKMS 编译时会链接 hello_world.o 到 hello_world.ko。
实现业务代码与内核ABI完全脱钩,充分利用DKMS优势的情况下,又能避免直接泄漏业务代码。
更多推荐



所有评论(0)