Dynamic Kernel Module Support (简体中文)
来自 Wikipedia:
- 动态内核模块支持 (DKMS) 是一个可以从位于内核源码树之外的内核模块源代码编译生成内核模块的程序框架。它可以使得在升级内核时,通过DKMS管理的内核模块自动重新构建以适应新的内核版本。
Contents
影响
使用DKMS的积极作用是通过DKMS管理的内核模块可以在升级内核时被自动重新编译。这意味这你不再需要等待某个公司,项目组或者包维护者释出新版本的内核模块。
消极作用是DKMS破坏了Pacman数据库,因为这样一来重新构建后的内核模块不再属于任何一个包,所以Pacman就不能再追逐它们。不过理论上,可以通过添加钩子函数来对此支持(see: FS#2985)。
安装
要想使DKMS模块可以在内核升级后重启时被自动重新构建,需要先开启dkms
系统服务。
有许多位于内核源码树之外的内核模块都有DKMS变体;有一些位于official repositories,大多数可以在这儿AUR找到。下面列出的是一小部分有DKMS变体的软件包
- AMD Catalyst: catalyst-dkmsAUR
- NVIDIA:
- VirtualBox, section VirtualBox#Hosts running a custom kernel[broken link: invalid section]
- VMware, section VMware#Using DKMS to manage the modules
升级
即使内核模块经常会在某个内核的大更新时被重新构建,不过也有某些特定时候需要对模块进行升级来处理内核变动,修复bug或者添加必要的新特性,这是可以考虑在重启系统之前升级DKMS包。
使用方法
如何手动调用DKMS:
可以通过执行以下命令来使能使用DKMS时的Tab补全:
# source /usr/share/bash-completion/completions/dkms
列出内核模块
列出当前模块的状态,版本,包括源码树内的模块:
$ dkms status
重新构建模块
为当前内核重新构建所有的模块:
# dkms autoinstall -k
或者重新构建某个特定的模块:
# dkms autoinstall -k 3.16.4-1-ARCH
为当前内核构建一个特定的模块(例如: 对于当前内核):
# dkms install -m nvidia -v 334.21
或者简单地:
# dkms install nvidia/334.21
构建一个可以兼容所有内核版本的模块:
# dkms install nvidia/334.21 --all
移除模块
移除一个内核模块(旧的内核模块并不会被自动移除):
# dkms remove -m nvidia -v 331.49 --all
或者简单的:
# dkms remove nvidia/331.49 --all
如果你卸载了dkms包,那么以前构建内核模块使用的相关文件信息就会丢失。如果这样,去/usr/lib/modules/KERNELVERSION-ARCH
下删除不再需要的文件和目录。
创建DKMS包
这儿的一些的指导方针可以在创建一个新的DKMS包时作为参考。
包名
DKMS的包的命名方式是:原始包名加"-dkms"后缀。
The variable $_pkgname
is often used below $pkgname
to describe the package name minus the "-dkms" suffix (e.g. _pkgname=${pkgname%-*}
). This is useful to help keep similarities between the original package PKGBUILD and the DKMS variant.
依赖
Dependencies should be inherited from the original version with dkms added and linux-headers removed (as it is listed by the dkms pacakge as optional).
源代码构建位置
构建模块所需源代码需要放在(这是DKMS构建模块时使用的默认目录):
/usr/src/PACKAGE_NAME-PACKAGE_VERSION
In the package directory, a DKMS configuration tells DKMS how to build the module (dkms.conf
), including the variables PACKAGE_NAME
and PACKAGE_VERSION
.
-
PACKAGE_NAME
- the actual project name (usually$_pkgname
or$_pkgbase
). -
PACKAGE_VERSION
- by convention this should also be the$pkgver
.
打补丁
为内核模块源代码打补丁既可以直接在PKGBUILD中进行,也可以通过dkms.conf
来进行。
.install 中模块的自动加载
模块的加载和卸载必须由用户自己来执行,设想一下,某个模块可能在加载的时候崩溃。
namcap 输出
namcap (它会试图检查一个包中的一般性错误和不符合标准的设定)在任何包中最好至少使用一次。然而,namcap至今仍然没有针对DKMS的特殊方针做更新。
例如,默认情况下,DKMS使用/usr/src/
,不过Namcap认为这不是一个标准目录,不符合这个reference。
例子
这儿有个根据包名字和版本来对dkms.conf
进行编辑的例子。
PKGBUILD
PKGBUILD
# Maintainer: foo <foo(at)gmail(dot)com> # Contributor: bar <bar(at)gmai(dot)com> _pkgbase=amazing pkgname=amazing-dkms pkgver=1 pkgrel=1 pkgdesc="The Amazing kernel modules (DKMS)" arch=('i686' 'x86_64') url="https://www.amazing.com/" license=('GPL2') depends=('dkms') conflicts=("${_pkgbase}") install=${pkgname}.install source=("${url}/files/tarball.tar.gz" 'dkms.conf' 'linux-3.14.patch') md5sums=(use 'updpkgsums') build() { cd ${_pkgbase}-${pkgver} # Patch patch -p1 -i "${srcdir}"/linux-3.14.patch # Build msg2 "Starting ./configure..." ./configure msg2 "Starting make..." make } package() { # Install msg2 "Starting make install..." make DESTDIR="${pkgdir}" install # Copy dkms.conf install -Dm644 dkms.conf "${pkgdir}"/usr/src/${_pkgbase}-${pkgver}/dkms.conf # Set name and version sed -e "s/@_PKGBASE@/${_pkgbase}/" \ -e "s/@PKGVER@/${pkgver}/" \ -i "${pkgdir}"/usr/src/${_pkgbase}-${pkgver}/dkms.conf # Copy sources (including Makefile) cp -r ${_pkgbase}/* "${pkgdir}"/usr/src/${_pkgbase}-${pkgver}/ }
dkms.conf
dkms.conf
PACKAGE_NAME="@_PKGBASE@" PACKAGE_VERSION="@PKGVER@" MAKE[0]="make --uname_r=$kernelver" CLEAN="make clean" BUILT_MODULE_NAME[0]="@_PKGBASE@" DEST_MODULE_LOCATION[0]="/kernel/drivers/misc" AUTOINSTALL="yes"
.install
此时可以使用dkms install
而不是depmod
来安装内核模块(dkms install
依赖dkms build
,而dkms build
依赖dkms add
):
amazing-dkms.install
# old version (without -$pkgrel): ${1%%-*} # new version (without -$pkgrel): ${2%%-*} post_install() { dkms install amazing/${1%%-*} } pre_upgrade() { pre_remove ${2%%-*} } post_upgrade() { post_install ${1%%-*} } pre_remove() { dkms remove amazing/${1%%-*} --all }