Kernel DKMS Package

Note: This document is under construction/revision

DKMS (Dynamic Kernel Module Support) is a system for automatically installing and rebuilding kernel modules that are maintained outside of the kernel tree to ensure that if a new kernel is installed that changes the ABI (Application Binary Interface), existing DKMS-managed modules are automatically built on the local PC against the new kernel's headers - saving the user from needing to manually rebuild the source or download an updated debian binary package./

This guide is intended to help developers and packagers understand how DKMS can help them quickly and easily prepare source packages. It is particularly focused on packagers preparing for Ubuntu PPA (Personal Package Archive) or official build uploads.

Preparing the Source

This will be a practical tutorial based on two web-cam drivers: r5u870 (Sony Vaio MotionEye) and ov51x-jpeg (Playstation EyeToy and Hercules Deluxe). The reason for using both is that they have slightly different configuration requirements - r5u870 installs two kernel modules.

Obtain the Source

We usually have the option of working from the project source version-control repository or a tarball archive.

Get The Latest Source

svn co http://svn.mediati.org/svn/r5u870/trunk r5u870

or

svn co svn://rastageeks.org/svn/ov51x-jpeg/trunk ov51x-jpeg

Install Source Archive

wget http://mediati.org/r5u870/r5u870-0.11.1.tar.gz
mkdir r5u870-0.11.1
tar -xzf r5u870-0.11.1.tar.gz -C r5u870-0.11.1

or

wget http://www.rastageeks.org/downloads/ov51x-jpeg/ov51x-jpeg-1.5.8.tar.gz
tar -xzf ov51x-jpeg-1.5.8.tar.gz

Source Directory Naming Convention

For debian packages the original source directory needs to be named <package>-<version>/ (e.g. r5u870-0.11.1/) so start by ensuring this is done or copy the existing source directory to a new one for the debianisation process.

If working from a version-control repository such as git, svn, cvs, etc., it is best to create a working copy for packaging:

pwd
/home/all/SourceCode/r5u870
cp -a . ../r5u870-0.11.1
cd ../r5u870-0.11.1

or

pwd
/home/all/Sourcecode/ov51-jpeg
cp -a . ../ov51x-jpeg-1.5.8
cd ../ov51x-jpeg-1.5.8

Removing Version-Control Repository Data

If working from a version-control system there are going to be hidden directories and files which need to be ignored. The safest way to ensure all the tools used during builds avoid these is to remove them.

pwd
/home/all/SourceCode/r5u870-0.11.1

ls -da .[^.]*
.cproject  .project  .svn

rm -rf .cproject .project .svn

or

pwd
/home/all/SourceCode/ov51x-jpeg-1.5.8

ls -da .[^.]*
.svn

rm -rf .svn

Prepare the Debian Package

Create Initial Debian Files

There are three methods for preparing the DKMS-managed Debian package. Which you use depends on your experience and the degree of control over the process you want. On balance I'd recommend the template-assisted manual approach as the starting-point for the debian files.

DKMS version 2.0.20.0 introduced support for preparing source packages using the mkdsc command. Unfortunately the version in Hardy LTS is the older v2.0.19.0. I've published v2.0.20 in my PPA for Gutsy, Hardy and Intrepid.

  • Warning: If you use the traditional Debian package preparation method (represented by the second and third methods offered here) you *will* need to modify the DKMS v2.0.20 mkdsc templates if you use them as a basis for the Debian/DKMS package. I've attached the modified template set. These are more suited to Ubuntu packaging, too. If used with the Template-Assisted method and the dkms_preprocess script (also attached) you'll have the best of both worlds. I'm hoping to get the support for installing unpacked source put back into DKMS and then this won't be an issue.

DKMS mkdsc Method

The DKMS tools provide a method for creating a debian source package using the mkdsc command. The essentials are:

$ dkms mkdsc -m ${PKG_NAME} -v ${PKG_VERSION} --source-only

Note: This will do a similar job to dh_make (described in detail next) but will install files tailored for DKMS use.

It is important to understand that dkms mkdsc only works with a package already added to the DKMS Tree. This also means you'll have to work with super-user commands and in the/usr/src/ directory and DKMS Tree, which is usually /var/lib/dkms/${PKG_NAME}/${PKG_VERSION}/

It will not work with familiar debian packaging tools that expect to be in the package source root directory and find a debian/ directory there.

One-time only, edit the files in /etc/dkms/template-dkms-mkdsc so they match your requirements. The alternative option is to create a template in the module source directory. In this case that would be /usr/src/ov51x-jpeg-1.5.8/ov51x-jpeg-dkms-mkdsc/ (Note: the debian/ directory is inside the template directory).

debian/changelog and debian/control will need the maintainer details. In addition debian/changelog will need the release changing from the debian-style "unstable" to an Ubuntu release such as "hardy" or "intrepid". Other files such as debian/copyright might benefit from some basic configuration too.

debian/dir ought to include the man-page directory - it is part of Debian policy for every package to contain a man-page:

/usr/src
/usr/share/man/man8

Note: dkms will pre-process all files in the debian/ directory and replace all occurances of the text DEBIAN_PACKAGE, MODULE_NAME, MODULE_VERSION and DATE_STAMP with module-specific values.

I've attached my modified source template - you will need this if you are working with the traditional packaging methods because the latest DKMS v2.0.20 assumes mkdsc has been used and cannot install a module from an unpacked /usr/src/ directory. You'll also find it a more complete and suitable basis for Ubuntu packaging.

It is easy to be caught out by the fact that mkdsc creates the final product. In other words, it does not leave behind a prepared debian/ directory and related files. They are only in the source archive it creates.

With that said, here's how it is done. First, copy the source-code to /usr/src/:

$ sudo cp -a . /usr/src/ov51x-jpeg-1.5.8

Now add the package to the DKMS tree

$ sudo dkms add -m ov51x-jpeg -v 1.5.8


Creating symlink /var/lib/dkms/ov51x-jpeg/1.5.8/source ->
                 /usr/src/ov51x-jpeg-1.5.8

DKMS: add Completed.

To create the debian source archive:

$ sudo dkms mkdsc -m ov51x-jpeg -v 1.5.8 --source-only

Using /etc/dkms/template-dkms-mkdsc
copying template...
modifying debian/changelog...
modifying debian/compat...
modifying debian/control...
modifying debian/copyright...
modifying debian/dirs...
modifying debian/postinst...
modifying debian/postrm...
modifying debian/prerm...
modifying debian/README.Debian...
modifying debian/rules...
gathering sources...
Marking /var/lib/dkms/ov51x-jpeg/1.5.8/source for archiving...


Tarball location: /var/lib/dkms/ov51x-jpeg/1.5.8/tarball/ov51x-jpeg-1.5.8.dkms.tar.gz

DKMS: mktarball Completed.

Copying DKMS tarball into DKMS tree...
Building source package... debian/rules clean
 dpkg-source -b ov51x-jpeg-dkms-1.5.8
 dpkg-genchanges -S >../ov51x-jpeg-dkms_1.5.8_source.changes
dpkg-genchanges: including full source code in upload

Moving built files to /var/lib/dkms/ov51x-jpeg/1.5.8/dsc...
Cleaning up temporary files...

DKMS: mkdsc Completed.

At this point the debian/ files are in /var/lib/dkms/ov51x-jpeg/1.5.8/dsc/ov51x-jpeg-dkms_1.5.8.tar.gz

It is important to realise mkdsc doesn't leave a debian/ directory behind so you've got to extract it from the archive.

$ sudo tar -xzf /var/lib/dkms/ov51x-jpeg/1.5.8/dsc/ov51x-jpeg-dkms_1.5.8.tar.gz -C /usr/src/ov51x-jpeg-1.5.8
$ sudo mv /usr/src/ov51x-jpeg-1.5.8/ov51x-jpeg-dkms-1.5.8 /usr/src/ov51x-jpeg-1.5.8/ov51x-jpeg-dkms-mkdsc

Finally, at this point, you've got a default debian package definition you can continue to work from.

Any changes to the debian files should now be made, such as defining the changes in the changelog, any specifics in the control, and the package author details in copyright and specific package information in README.Debian.

Template-Assisted method

My personal preference when preparing packages is to work with user privileges only, and to work in scratch directories rather than in system locations. My experience of using mkdsc is it hinders rather than helps the package-preparation process. It is especially annoying if you've got a set of scripts to automate package build and test which assume they're running in the package-root directory.

On balance I'd rather copy the /etc/dkms/template-dkms-mkdsc/debian/ templates to the package's debian/ directory and pre-process them with this little bash script (dkms_preprocess) that can be run from the package-root:

#!/bin/bash
# pre-process DKMS debian templates
# hacked from /usr/sbin/dkms
# Copyright 2008 TJ <ubuntu@tjworld.net>
# Licensed on the terms of the GNU GPL version 2

cp -a /etc/dkms/template-dkms-mkdsc/debian .

dir="${PWD##*/}"
module="${dir%-*}"
debian_package="${module}-dkms"
module_version="${dir##*-}"
date_str="$(date -R)"

echo "Package $debian_package for module $module version $module_version dated $date_str"

pushd debian > /dev/null
for file in $(find . -type f); do
    echo "Modifying ${file##*/}"
    sed -i -e "s/DEBIAN_PACKAGE/$debian_package/g" \
        -e "s/MODULE_NAME/$module/g" \
        -e "s/MODULE_VERSION/$module_version/g" \
        -e "s/DATE_STAMP/$date_str/" "$file"
        if [ "${file%.*}" == "./MOD_NAME" ]; then
                echo "Renaming ${file} to ./${module}.${file##*.}"
                mv "$file" "./${module}.${file##*.}"
        fi
        if [ "${file%.*}" == "./PKG_NAME" ]; then
                echo "Renaming: ${file} to ./${debian_package}.${file##*.}"
                mv "$file" "./${debian_package}.${file##*.}"
        fi
done
popd > /dev/null

echo "Setting executable permissions."
chmod 755 debian/rules debian/${debian_package}.postinst debian/${debian_package}.prerm debian/${debian_package}.postrm
mkdir -p debian/patches

Running it:

$ pwd
/home/all/SourceCocde/ov51x-jpeg-1.5.8
$ dkms_preprocess
Package ov51x-jpeg-dkms for module ov51x-jpeg version 1.5.8 dated Wed, 13 Aug 2008 16:44:16 +0100
Modifying control
Modifying MOD_NAME.8
Renaming ./MOD_NAME.8 to ./ov51x-jpeg.8
Modifying PKG_NAME.postinst
Renaming: ./PKG_NAME.postinst to ./ov51x-jpeg-dkms.postinst
Modifying PKG_NAME.postrm
Renaming: ./PKG_NAME.postrm to ./ov51x-jpeg-dkms.postrm
Modifying README.Debian
Modifying rules
Modifying changelog
Modifying copyright
Modifying PKG_NAME.install
Renaming: ./PKG_NAME.install to ./ov51x-jpeg-dkms.install
Modifying PKG_NAME.prerm
Renaming: ./PKG_NAME.prerm to ./ov51x-jpeg-dkms.prerm
Modifying compat
Modifying dirs
Setting executable permissions.

After that, all the regular debian packaging tools and scripts can be used as normal.

Debhelper dh_make Method

This is an alternative to the DKMS mkdsc method detailed above.

Use the debhelper tool to create a GPL-ed CDBS (Common Debian Build System) package. I use CDBS because debian/rules is simple and it handles patching easily too:

$ dh_make --cdbs --copyright gpl -f ../${PKG_NAME}_${PKG_VERSION}.orig.tar.gz

There is now a debian/ directory with a collection of example files:

$ ls debian
changelog  cron.d.ex           emacsen-remove.ex   manpage.1.ex     postinst.ex  r5u870-default.ex   watch.ex
compat     dirs                emacsen-startup.ex  manpage.sgml.ex  postrm.ex    r5u870.doc-base.EX
control    docs                init.d.ex           manpage.xml.ex   preinst.ex   README.Debian
copyright  emacsen-install.ex  init.d.lsb.ex       menu.ex          prerm.ex     rules

Because this is a kernel package most of the example files can be deleted:

$ cd debian
$ rm cron.d.ex dirs docs emacs* init* manpage.sgml.ex mapage.xml.ex menu.ex postrm.ex preinst.ex *-default.ex *.doc-base.EX watch.ex

Configure DKMS

Create debian/dkms.conf and define the DKMS options for the package. During package-build this file will be copied to the installation directories (usr/src/${PKG_NAME}-${PKG_VERSION}) using a custom dh_install target in rules. The directives in the file are shell environment variable assignments:

PACKAGE_VERSION="0.11.1"
PACKAGE_NAME="r5u870"
CLEAN="make clean"
BUILT_MODULE_NAME[0]="usbcam"
BUILT_MODULE_LOCATION[0]="usbcam/"
DEST_MODULE_LOCATION[0]="/kernel/../extra/usbcam/"
BUILT_MODULE_NAME[1]="r5u870"
DEST_MODULE_LOCATION[1]="/kernel/../extra/"
MAKE[1]="make KVER=$kernelver src=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build"
AUTOINSTALL="yes"

Because DKMS will do a manual out-of-tree build the existing Makefile targets (all, install, etc.) are used. Therefore, for each kernel module in the package (in this case usbcam.ko and r5u870.ko) a set of build directives is required that are assigned to array elements in each variable. In this case element [0] is the usbcam module and [1] is the r5u870 module. They should be ordered with prerequisites first (hence [0] is usbcam).

Because usbcam is in a sub-directory this is reflected with BUILT_MODULE_LOCATION[0]. Both modules have a DEST_MODULE_LOCATION[...] that defines where the package's own Makefile install target would install them (/lib/modules/<kernel-version>/extra in this case).

The r5u870 MAKE[1] directive defines the make command and options and accompanying Makefile variables to set. In this case KVER and src are set so that the current Makefile variable assignments will operate correctly. DKMS provides and sets the variables $kernelver and $dkms_tree to enable the Makefile to figure out the correct locations, if necessary.

For ov51x-jpeg:

PACKAGE_VERSION="1.5.8"
PACKAGE_NAME="ov51x-jpeg"
CLEAN="make clean"
BUILT_MODULE_NAME[0]="ov51x-jpeg"
DEST_MODULE_LOCATION[0]="/kernel/../extra/"
MAKE[0]="make -d OVCAM_KVER=$kernelver"
AUTOINSTALL="yes"

Once dkms.conf has been created the only thing that will need changing is to increment PACKAGE_VERSION to reflect changes in the upstream versioning. PACKAGE_NAME is the simple name the package is known as.

CLEAN defines the command to use to clean the build location. AUTOINSTALL ensures that DKMS will both build and install the module when the package is installed using the package manager.

Customise Debian Files

Edit copyright and ensure the authors and dates are correct. In the following text PKG_NAME="r5u870-dkms" and MOD_NAME="r5u870".

Changelog

Edit changelog and correct the version and release strings. The version string needs to include the ubuntu version (and if this is a PPA package, ~ppa version) so for example:

r5u870 (0.11.1-1) unstable; urgency=low

becomes

r5u870-dkms (0.11.1-0ubuntu1~ppa1h) hardy; urgency=low

The version string 0ubuntu1~ppa1h is read as:

  • 0 = Not based on a debian package (otherwise this would be the debian package version number)

  • ubuntu = This is an Ubuntu package

  • 1 = Version 1 of the Ubuntu package

  • ~ = Means that this has to be ordered "before" any package with the same Ubuntu version that has no ~ suffix. Thereby if there is ever an ...ubuntu1 it will replace ...ubuntu1~ppa1h as ~ orders "before" it.

  • ppa = This is a Personal Package Archive package, not one from the official Ubuntu repositories

  • 1 = This is the first version of the PPA package. Increment this each time a change is made and new upload to the PPA performed.

As a further enhancement I usually suffix the ~ppaX version with a single letter that represents the release the package is for. This solves an annoying issue when building the same package for multiple releases (e.g. gutsy, hardy, intrepid) where the packages would otherwise have to have different version-numbers in order for the PPA to accept them. So:

  • h = The release this package is for (g = Gutsy, h = Hardy, i = Intrepid, etc.)

I wrote the ppa_publish shell script to automatically build and publish source packages to the PPA for multiple releases.

Control

A developing convention for kernel source packages (which are source-code) is to set the Package name as ${PGK_NAME}-kernel-source (e.g. r5u870-kernel-source). However, DKMS has adopted the convention of suffixing the package name with -dkms (e.g. r5u870-dkms). On balance I think the -dkms suffix is preferable since it quickly indicates in a package-name that the module is portable across kernel versions.

  • Architecture should be set to any so that the PPA buildd's create an _all.deb package. If this was set to source, as might be expected based on the Debian policy, the PPA would reject the upload.

Because this is a source package there are no shared-library Depends - instead this is set to dkms since DKMS is required to build and install the kernel modules when the package has been installed. In later version (v2.0.20+) it also depends on bash. Build-Depends should probably include linux-headers-generic although I originally missed it off and the PPA builds were still successful.

Ensure Standards-Version is up-to-date. The current version is 3.7.3. Priority will probably be extra or optional. You'll need to decide which Section to allocate the package to - possibly admin but you can look at other packages in the repositories using Synaptic or aptitude or check the http://packages.ubuntu.com/ Ubuntu Packages archive directly. In the case of r5u870 it is a webcam driver and I saw that gspca is in graphics so used that too. Finally, add a useful description of the package that is displayed by package managers when users examine the package.

So the final control file for r5u870 looks like this:

Source: r5u870-dkms
Section: graphics
Priority: optional
Maintainer: TJ <ubuntu@tjworld.net>
Build-Depends: cdbs, debhelper (>= 5), linux-headers-generic
Standards-Version: 3.7.3

Package: r5u870-dkms
Architecture: all
Depends: dkms
Description: Source code for Ricoh r5u870 Camera Driver.
 Kernel driver for a range of Sony Vaio Motion Eye, HP Pavilion and other
 integrated Ricoh r5u870 cameras:
 05ca:1810  HP Pavilion Webcam - UVC OK
 05ca:1812  HP Pavilion Webcam - UVC Pavilion DV6502AU In-progress
 05ca:1830  Sony Visual Communication Camera VGP-VCC2  VAIO SZ  OK
 05ca:1832  Sony Visual Communication Camera VGP-VCC3  VAIO UX  OK
 05ca:1833  Sony Visual Communication Camera VGP-VCC2  VAIO AR1  OK
 05ca:1834  Sony Visual Communication Camera VGP-VCC2  VAIO AR2  OK
 05ca:1835  Sony Visual Communication Camera VGP-VCC5  VAIO SZ  OK
 05ca:1836  Sony Visual Communication Camera VGP-VCC4  VAIO FE  OK
 05ca:1837  Sony Visual Communication Camera VGP-VCC4  VAIO FZ  OK
 05ca:1839  Sony Visual Communication Camera VGP-VCC6  VAIO CR  OK
 05ca:1841  Fujitsu F01 UVC  Unknown  In-progress
 05ca:183a  Sony Visual Communication Camera VGP-VCC7  VAIO SZ/TZ11  OK
 05ca:183b  Sony Visual Communication Camera VGP-VCC8  VAIO FZ  OK
 05ca:1870  HP Pavilion Webcam / HP Webcam 1000  OK 

Dh_install Directives

The file ${PKG_NAME}.install feeds the call to dh_install (made by CDBS) and declares origin and destination of any files that need copying into the installation directories.

*                       usr/src/r5u870-0.11.1
debian/dkms.conf        usr/src/r5u870-0.11.1

Note: in this case the rule for dkms.conf will be ignored due to an --exclude= option defined in rules but it is retained here for clarity and accuracy. A source package with its source files in sub-directories would need this.

README.Debian

This is pretty simple:

r5u870 for Debian
-----------------

Please see ./README for a description of the r5u870 software.

The Debian r5u870 DKMS source package provides:,

 * r5u870-dkms, which provides the source for the kernel modules

 -- TJ <ubuntu@tjworld.net>  Tue, 22 Jul 2008 02:10:21 +0100

Post Install Script

After the package manager (apt-get, aptitude, Synaptic) has installed the package DKMS needs to be told about the new package and triggered to build and install it. The file ${PKG_NAME}.postinst does this (this is simple version of the all-singing all-dancing version in the DKMS templates):

# Copyright (C) 2002-2005 Flavio Stanchina
# Copyright (C) 2005-2006 Aric Cyr
# Copyright (C) 2007 Mario Limonciello

CVERSION=`dpkg-query -W -f='${Version}' r5u870-dkms | awk -F "-" '{print $1}' | cut -d\: -f2`

#DEBHELPER#

case "$1" in
        configure)
                echo "Adding Module to DKMS build system"
                dkms add -m r5u870 -v $CVERSION > /dev/null
                echo "Doing initial module build"
                dkms build -m r5u870 -v $CVERSION > /dev/null
                echo "Installing initial module"
                dkms install -m r5u870 -v $CVERSION --force > /dev/null
                echo "Done."
        ;;
esac

Note: Ensure the correct package name replaces all mentions of r5u870

Pre Remove Script

When the package is about to be removed by the package manager DKMS needs to be instructed to remove the module from its list. The file ${PKG_NAME}.prerm does this (a simpler version of the one in the DKMS templates):

# Copyright (C) 2002-2005 Flavio Stanchina
# Copyright (C) 2005-2006 Aric Cyr
# Copyright (C) 2007-2008 Mario Limonciello

#DEBHELPER#

CVERSION=`dpkg-query -W -f='${Version}' r5u870-dkms | awk -F "-" '{print $1}' | cut -d\: -f2`
case "$1" in
    remove|upgrade)
                echo "Removing all DKMS Modules"
                dkms remove -m r5u870 -v $CVERSION --all > /dev/null
                echo "Done."
        ;;
esac

Note: Ensure the correct package name replaces all mentions of r5u870

Man Page

Rename the example manpage.1.ex:

$ mv manpage.1.ex ${MOD_NAME}.8

Note: Section number 8 (Administration tools) seems most suitable for a kernel module.

Now modify the template to suit the package. Here's how r5u870.8 looks:

.TH R5U870 8 2008-07-22 "r5u870" "Ricoh r5u870 kernel module"
.SH NAME
r5u870 \-   Ricoh r5u870 video camera driver
.SH DESCRIPTION
.I  r5u870
 DKMS Kernel module for a range of Sony Vaio Motion Eye, HP Pavilion and other
 integrated Ricoh r5u870 cameras:

 05ca:1810      HP Pavilion Webcam - UVC                OK
 05ca:1812      HP Pavilion Webcam - UVC        Pavilion DV6502AU       In-progress
 05ca:1830      Sony Visual Communication Camera VGP-VCC2       VAIO SZ         OK
 05ca:1832      Sony Visual Communication Camera VGP-VCC3       VAIO UX         OK
 05ca:1833      Sony Visual Communication Camera VGP-VCC2       VAIO AR1        OK
 05ca:1834      Sony Visual Communication Camera VGP-VCC2       VAIO AR2        OK
 05ca:1835      Sony Visual Communication Camera VGP-VCC5       VAIO SZ         OK
 05ca:1836      Sony Visual Communication Camera VGP-VCC4       VAIO FE         OK
 05ca:1837      Sony Visual Communication Camera VGP-VCC4       VAIO FZ         OK
 05ca:1839      Sony Visual Communication Camera VGP-VCC6       VAIO CR         OK
 05ca:1841      Fujitsu F01 UVC         Unknown         In-progress
 05ca:183a      Sony Visual Communication Camera VGP-VCC7       VAIO SZ/TZ11    OK
 05ca:183b      Sony Visual Communication Camera VGP-VCC8       VAIO FZ         OK
 05ca:1870      HP Pavilion Webcam / HP Webcam 1000             OK 
.TP
.B More information
r5u870 maintainer: http://wiki.mediati.org/R5u870
.SH AUTHORS
Alex Hixon, TJ, Sam Revitch

Dir

Each directory that will be touched by the installation should be listed in dirs. In this case it is relatively simple:

usr/share/man/man8
usr/src

Rules

If using CDBS rules is very simple. If using (or planning for eventually using) a patch system an additional include is all it takes.

Alert: If preparing for PPA upload do not use the makefile.mk include since this will cause the buildd to try and build against the running kernel (on the buildd that is currently 2.6.16.51).

# managed by CDBS

include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/rules/simple-patchsys.mk

We need to add some additional settings in order to support the DKMS package layout:

DEB_INSTALL_MANPAGES_r5u870-dkms="debian/r5u870.8"
DEB_DH_INSTALL_ARGS=--exclude=debian/

SRC_VERSION := $(shell dpkg-parsechangelog | grep '^Version:' | cut -d' ' -f2 | cut -d- -f1 | cut -d\: -f2)
binary-install/r5u870-dkms::
        cp $(CURDIR)/debian/dkms.conf $(CURDIR)/debian/$(cdbs_curpkg)/usr/src/r5u870-$(SRC_VERSION)

The first line defines the name of the manual page that will be built. The second line ensures that dh_install doesn't copy any files from the debian/ directory to the installation location. This is needed because the original package has all its files in the root of the package tree (rather than in a sub-directory such as src/). When dh_install runs and processes the ${PKG_NAME}.install instructions it has to copy all the source files to the installation location. Using dh_install --exclude= is an easy way to ensure debian/ isn't installed.

In the case of DKMS however, the package needs to install debian/dkms.conf. This is the reason for the final set of instructions. the binary-install/r5u870-dkms target causes the file to be copied into the correct installation location after dh_install ignored it.

  • Note: If you want to find out other debhelper dh_* script variables to over-ride you'll need to read the CDBS script in /usr/share/cdbs/1/rules/debhelper.mk. It is quite simple then to figure out which variables need setting for each aspect of the debhelper processes. Here's a snippet:

dh_installdocs -p$(cdbs_curpkg) $(DEB_INSTALL_DOCS_ALL) $(DEB_INSTALL_DOCS_$(cdbs_curpkg)) 
dh_installexamples -p$(cdbs_curpkg) $(DEB_INSTALL_EXAMPLES_$(cdbs_curpkg))
dh_installman -p$(cdbs_curpkg) $(DEB_INSTALL_MANPAGES_$(cdbs_curpkg)) 
dh_installinfo -p$(cdbs_curpkg) $(DEB_INSTALL_INFO_$(cdbs_curpkg)) 
dh_installmenu -p$(cdbs_curpkg) $(DEB_DH_INSTALL_MENU_ARGS)
dh_installcron -p$(cdbs_curpkg) $(DEB_DH_INSTALL_CRON_ARGS)
dh_installinit -p$(cdbs_curpkg) $(if $(DEB_UPDATE_RCD_PARAMS),--update-rcd-params="$(call cdbs_strip_quotes, \
  $(DEB_UPDATE_RCD_PARAMS))",$(if $(DEB_UPDATE_RCD_PARAMS_$(cdbs_curpkg)), \
  --update-rcd-params="$(call cdbs_strip_quotes,$(DEB_UPDATE_RCD_PARAMS_$(cdbs_curpkg)))")) \
  $(DEB_DH_INSTALLINIT_ARGS) 
dh_installdebconf -p$(cdbs_curpkg) $(DEB_DH_INSTALLDEBCONF_ARGS)
dh_installemacsen -p$(cdbs_curpkg) $(if $(DEB_EMACS_PRIORITY),--priority=$(DEB_EMACS_PRIORITY)) $(if $(DEB_EMACS_FLAVOR), \
  --flavor=$(DEB_EMACS_FLAVOR)) $(DEB_DH_INSTALLEMACSEN_ARGS)
dh_installcatalogs -p$(cdbs_curpkg) $(DEB_DH_INSTALLCATALOGS_ARGS)
dh_installpam -p$(cdbs_curpkg) $(DEB_DH_INSTALLPAM_ARGS)
dh_installlogrotate -p$(cdbs_curpkg) $(DEB_DH_INSTALLLOGROTATE_ARGS)
dh_installlogcheck -p$(cdbs_curpkg) $(DEB_DH_INSTALLLOGCHECK_ARGS)
dh_installmime -p$(cdbs_curpkg) $(DEB_DH_INSTALLMIME_ARGS)
dh_installchangelogs -p$(cdbs_curpkg) $(DEB_DH_INSTALLCHANGELOGS_ARGS) $(DEB_INSTALL_CHANGELOGS_ALL) \
  $(DEB_INSTALL_CHANGELOGS_$(cdbs_curpkg))
$(if $(wildcard /usr/bin/dh_installudev),dh_installudev -p$(cdbs_curpkg) $(DEB_DH_INSTALLUDEV_ARGS))
dh_install -p$(cdbs_curpkg) $(if $(DEB_DH_INSTALL_SOURCEDIR),--sourcedir=$(DEB_DH_INSTALL_SOURCEDIR)) $(DEB_DH_INSTALL_ARGS)
dh_link -p$(cdbs_curpkg) $(DEB_DH_LINK_ARGS) $(DEB_DH_LINK_$(cdbs_curpkg))

Makefile Out-Of-Tree Build Detection Variable

The original source should be checked to ensure that it builds correctly out-of-tree. This will mean that the Makefile must have additional targets and can detect when it is built separately from the kernel itself. There are many variation on the steps to do that. There are several gotchyas that need to be addressed to ensure the package will build using DKMS. For an example see section 4.1 of the kernel documentation (Documentation/kbuild/makefiles.txt)

The primary issue is the Makefile detection of an in-tree or out-of-tree build. It is often done by checking for an empty/undefined variable that is always set by Kbuild (the kernel build system).

  • E.g.

ifneq ($(KERNELRELEASE),)
include $(src)/Kbuild
else

all::

As I discovered after several hours of frustration when DKMS failed to build the package, detecting KERNELRELEASE causes the DKMS build to fail. I found that testing an alternative variable, PATCHLEVEL, solved this issue.

  • Note: The reason for this is confusing since DKMS sets KERNELRELEASE which triggers an in-kernel build which fails. I'm currently having a discussion about this with Mario and will clarify the situation once we've concluded.

This is the only change I had to make to the original source Makefile. It might be necessary to apply a debian patch during build to fix this.

This is an example of a flexible Makefile:

V ?= 0
MDIR := extra

KVER ?= $(shell uname -r)
KDIR ?= /lib/modules/$(KVER)/build
FWDIR ?= /lib/firmware

FWFILES = r5u870_1830.fw r5u870_1832.fw r5u870_1833.fw r5u870_1834.fw r5u870_1835.fw \
 r5u870_1836.fw r5u870_1870_1.fw r5u870_1870.fw r5u870_1810.fw r5u870_183a.fw r5u870_183b.fw r5u870_1839.fw 

ifneq ($(PATCHLEVEL),)
include $(src)/Kbuild
else

all::
        $(MAKE) -C $(KDIR) M=$(CURDIR) V=$(V) modules

install:: all
        $(MAKE) INSTALL_MOD_PATH=$(DESTDIR) INSTALL_MOD_DIR=$(MDIR) \
                -C $(KDIR) M=$(CURDIR) modules_install

clean::
        $(MAKE) -C $(KDIR) M=$(CURDIR) clean
        rm -f Module.symvers

endif

install::
        install -m 0644 -o root -g root $(FWFILES) $(FWDIR)
        /sbin/depmod -a

Alert: Note the use of ?= variable assignments. This causes make to only define the variable if it is currently undefined. This is very useful in many kernel build situations, but is particularly useful with DKMS since make options in dkms.conf can specifically set these variables.

It includes the Kbuild file. This will first build the files in the usbcam/ directory (which has its own Makefile) then the files in the current directory:

include $(src)/debug.mk
obj-m += usbcam/ r5u870.o

Which in turn includes the debug.mk file that specifies alternate build options (which I use for debugging):

# EXTRA_CFLAGS += -DCONFIG_USB_USBCAM_DEBUG

Alert: Knowing about this nested build will be very important later when defining the DKMS make options in dkms.conf. It is important in dkms.conf to ensure that the prerequisites (in this case, usbcam/) are built before the main driver.

For the ov51x-jpeg Makefile some patching needs to be done to allow existing variable values to be inherited (using ?= instead of :=). I altered Makefile then created the patch:

pwd
/home/all/SourceCode/ov51x-jpeg-1.5.8

diff -Nu ../ov51x-jpeg/Makefile ../ov51x-jpeg-1.5.8/Makefile >debian/patches/01_dkms_makefile_compatibility.patch
# remove the leading ../ from the patch paths
sed -i 's,^\(--- \|+++ \)\.\./\(.*\)$,\1\2,' debian/patches/01_dkms_makefile_compatibility.patch

And now reverse the patch to return the debianised source-code to virgin state:

patch -R -p1 < debian/patches/01_dkms_makefile_compatibility.patch

Build Package

This step is for local testing before the source package is uploaded to the PPA.

Make sure to be in the root directory of the package:

pwd
/home/all/SourceCode/r5u870-0.11.1

Use the regular Debian build process:

fakeroot debian/rules clean
fakeroot debian/rules binary

If the build was successful the binary target should report:

dpkg-deb: building package `r5u870-dkms' in `../r5u870-dkms_0.11.1-0ubuntu1~ppa1h_all.deb'.

It is always best to do a build test in a clean environment. I use pbuilder wrapped in custom scripts so I can have one package covering all releases. The changelog has its version and release re-written for the release I'm testing:

$ build_test gutsy
...
$ build_test hardy
...
$ build_test intrepid
...

Test Package

Now test the actual installation and triggering of DKMS:

sudo dpkg -i ../${PKG_NAME}_${PKG_VERSION}-0ubuntu1~ppa1h_all.deb

Selecting previously deselected package r5u870-dkms.
(Reading database ... 155086 files and directories currently installed.)
Unpacking r5u870-dkms (from .../r5u870-dkms_0.11.1-0ubuntu1~ppa1h_all.deb) ...
Setting up r5u870-dkms (0.11.1-0ubuntu1~ppa1h) ...
Adding Module to DKMS build system
Doing initial module build
Installing initial module
Done.

Create Source Package

Now the package is known working a source package needs creating for upload to the PPA buildd system:

debuild -S -sa
...
Successfully signed dsc and changes files

Upload Source Package

Upload the package to the PPA:

dput ${PPA} ../${PKG_NAME}_${PKG_VERSION}-0ubuntu1~ppa1h_source.changes

Check the PPA Build Status

On the PPA status page (in my case my PPA) you'll see the status of the package. It will confusingly report only doing the i386 build. This is a bugette - it should report building all since the source is architecture-agnostic. Once the build has finished the package details will correctly show that the _all.deb has been created:

Publishing details

    * Published 13 hours ago

Changelog

r5u870 (0.11.1-0ubuntu1~ppa1h) hardy; urgency=low

  * Initial DKMS release
  * New upstream release 0.11.1

 -- TJ <ubuntu@tjworld.net>   Tue, 22 Jul 2008 02:10:21 +0100

Builds

    * [FULLYBUILT] i386

Download files from Librarian

    * r5u870-dkms_0.11.1-0ubuntu1~ppa1h_all.deb (154.2 KiB)
    * r5u870_0.11.1-0ubuntu1~ppa1h.diff.gz (1.9 KiB)
    * r5u870_0.11.1-0ubuntu1~ppa1h.dsc (599 bytes)
    * r5u870_0.11.1.orig.tar.gz (145.4 KiB)

Conclusions

There are a lot of relatively minor configuration issues that can lead to DKMS failing to build the package. If there are problems with failed DKMS builds and the /var/lib/dkms/${PKG_NAME}/${PKG_VERSION/build/make.log is almost empty of useful information add the make debug option (-d) to the dkms.conf MAKE="" configurations. That'll ensure make reports everything it is doing to the log-file - essential when builds mysteriously fail with DKMS:

MAKE[1]="make -d KVER=$kernelver src=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build"


CategoryKernel

Kernel/DkmsDriverPackage (last edited 2021-08-10 08:25:40 by paelzer)