DKMS package guidelines

From ArchWiki
Arch package guidelines

32-bitCLRCMakeCrossDKMSEclipseElectronFontFree PascalGNOMEGoHaskellJavaKDEKernel modulesLispMesonMinGWNode.jsNonfreeOCamlPerlPHPPythonRRubyRust - SecurityShellVCSWebWine

Here are some guidelines to follow when creating a DKMS package.

Package name

DKMS packages are named by appending "-dkms" to the original package name.

The variable $_pkgname is often used below $pkgname to describe the package name minus the "-dkms" suffix (e.g. _pkgname="${pkgname%-*}")

Dependencies

Add dkms to depends array. This is important because this will provide tools and hooks that will rebuild the kernel driver provided by the -dkms package whenever the kernel is updated.

Do not include linux-headers – or any other Linux header package – to the PKGBUILD. These headers are already listed as optional dependencies of dkms and each kernel package has its own header package, so including header package dependency in the -dkms package is both unnecessarily redundant and restricting.

Source location

The package should install the kernel module's source files into:

/usr/src/PACKAGE_NAME-PACKAGE_VERSION

where PACKAGE_NAME and PACKAGE_VERSION are the kernel module's name and version.

It is highly recommended to set PACKAGE_NAME with the value of $_pkgname (See #Package name), and PACKAGE_VERSION with $pkgver.

Note: There is no need to build the kernel module's sources file nor install them; this is done automatically whenever the Linux kernel is updated thanks to a pacman hook in dkms.

Patching

The sources can be patched either directly in the PKGBUILD or through dkms.conf.

If patching through dkms.conf, make sure to install the patches into /usr/src/PACKAGE_NAME-PACKAGE_VERSION/patches/ directory and to add a PATCH[number]=patch_filename for each patch to be applied, replacing number with a incremental value starting at 0. See dkms(8) § DKMS.CONF for more information.

Module loading automatically in .install

Do not use .install file to load or unload modules. Leave it to the user, since there is a possibility a module may crash when loaded.

Also do not call dkms as it is automatically done via pacman hook provided by dkms. This hook runs dkms install and dkms remove leaving no manual task for the package maintainer.

Note: dkms install is making sure depmod is called at the end of its process. dkms install depends on dkms build (to build the source against the current kernel), which itself depends on dkms add (to add a symlink from /var/lib/dkms/PACKAGE_NAME/PACKAGE_VERSION/source to /usr/src/PACKAGE_NAME-PACKAGE_VERSION).

Example

Here is an example package that edits dkms.conf according to the package name and version, and install module blacklist configuration file.

For other example of (real) packages, search -dkms in official repositories and -dkms in AUR.

PKGBUILD

PKGBUILD
# Maintainer: foo <foo(at)example(dot)org>
# Contributor: bar <bar(at)example(dot)org>

_pkgbase=example
pkgname=example-dkms
pkgver=1
pkgrel=1
pkgdesc="The Example kernel modules (DKMS)"
arch=('x86_64')
url="https://www.example.org/"
license=('GPL2')
depends=('dkms')
conflicts=("${_pkgbase}")
install=${pkgname}.install
source=("${url}/files/tarball.tar.gz"
        'dkms.conf'
        "${pkgname}.conf"
        'linux-3.14.patch')
md5sums=(use 'updpkgsums')

prepare() {
  cd ${_pkgbase}-${pkgver}

  # Patch
  patch -p1 -i "${srcdir}"/linux-3.14.patch
}

package() {
  # 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}/

  # Blacklists conflicting module
  install -Dm644 ${pkgname}.conf "${srcdir}/usr/lib/modprobe.d/${pkgname}.conf"
}

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

This example shows a message on post-install and post-upgrade that suggests unloading a conflicting module (example-conflicting-module) and then loading this package's module (example) for immediate use, when the user do not want to reboot the system at this moment.

example.install
post_install() {
  cat<<EOF

Unload and load kernel modules:

  rmmod example-conflicting-module
  modprobe example

EOF
}

post_upgrade() {
  post_install
}

Module blacklist conf

When it is known that example-conflicting-module conflicts with this package's example module, it should be blacklisted:

example-dkms.conf
blacklist example-conflicting-module