wiki:Linux/Ubuntu/Kernel/BuildDebianDKMSPackages

Build Debian DKMS Packages

Introduction

DKMS ( Dynamic Kernel Module Support) is a Dell-sponsored 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.

I hit many stumbling blocks before achieving a successful DKMS install so it seems a good idea to document the process for other Ubuntu packages to remove the headaches of the learning-curve.

Ubuntu

Ubuntu adopted DKMS with Gutsy and it is used extensively by Hardy and Intrepid. It is also used (or desired to be used) by projects, teams and hackers who want to create kernel modules that users can easily download and install without knowing (or having to learn) how to build the Linux kernel.

The DKMS-managed package can be provided by the standard Debian repository system and installed using apt-get, aptitude, Synaptic, etc..

The essence of a DKMS-prepared package is that it is source code not binary - somewhat counter-intuitive for repository packages. There are few if any guides on how to prepare a kernel module package for Ubuntu. The only resource I could find that showed the process and specifics of preparing a debian package was a video  featuring Ben Collins (Ubuntu Kernel Team) doing a presentation showing him creating a package at the Ubuntu Kernel Sprint in July 2008. Even that only gave a rushed overview but it gave me enough of an outline to prepare my first DKMS package for the Ricoh r5u870 camera driver that supports most Sony Vaio Motion Eye cameras.

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

Preparing the Debian Package

Create Initial Debian Files

There are three methods for preparing the DKMS-managed 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 introduce 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.

DKMS mkdsc Method

The DKMs tools provide a method for creating a debian 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 occurences of the text DEBIAN_PACKAGE, MODULE_NAME, MODULE_VERSION and DATE_STAMP with module-specific values.

I've attached my modified /etc/dkms/template-dkms-mkdsc/debian/ Download template - you might 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 manually pre-process them with this little script (dkms_preprocess Download) 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 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"

Once 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.

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 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 OVCAM_KVER=$kernelver"
AUTOINSTALL="yes"

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.

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 packge, ~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
  • ~ = Tells package installer to replace this package by any package with the same Ubuntu version that has no ~ suffix
  • 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 DKMS packages (which are source-code) is to set the Package name as ${PGK_NAME}-kernel-source. E.g. r5u870-kernel-source. However, for DKMS packages it is preferable to use ${PGK_NAME}-dkms to indicate this is a specialised source package.

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. 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  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}-dkms.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.

README.Debian

This is pretty simple:

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

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

The Debian r5u870 source package provides two packages,

 1) r5u870, which the provides the kernel driver
 2) r5u870-kernel-source, 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:

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

CVERSION=`dpkg-query -W -f='${Version}' r5u870-kernel-source | 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:

#!/bin/sh
# 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-kernel-source | 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 ${PKG_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
 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 
.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).

#!/usr/bin/make -f
# 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.

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'll spare the explanation but I found that detecting an alternative variable, PATCHLEVEL, solved this issue.

This is the only change I had to make to the original source Makefile. In this case I'm arranging for the change to be made to the upstream package but for other packages it might be necessary to apply a debian patch during build.

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-kernel-source_0.11.1-0ubuntu1~ppa1h_all.deb'.

Test Package

Now test the actual installation and triggering of DKMS:

$ sudo dpkg -i ../r5u870-dkms_0.11.1-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 intuitivenipple-ppa ../r5u870_0.11.1-0ubuntu1~ppa1h_source.changes

Check the PPA Build Status

On the PPA status page (in my case  https://launchpad.net/~intuitivenipple/+archive) 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 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"

Attachments