Upstream-side: ABI version numbers

The X server defines several ABI version numbers in the hw/xfree86/common/xf86Module.h header, through the SET_ABI_VERSION(maj,min) macro. In this document, the focus is on ABI_VIDEODRV_VERSION and ABI_XINPUT_VERSION, which are respectively about video drivers and input drivers.

An example of input ABI is 12.1, 12 being the major, 1 being the minor.

Like in usual shared libraries, the major is bumped when interfaces are broken. There’s no compatibility at all in that case.

The minor gets bumped when interfaces are added. In other words, if a driver is working with x.y, it should also work with higher minors: x.z; z>y. The converse is not true, if a driver requires a given minor (for example because it needs a new feature, like MultiTouch), it won’t work with lower minors (which didn’t provide the needed feature). Put another way: we have ascending compatibility with the minors.

Conclusion: We need to keep track of both major and minor.

Thanks to pkg-config we can query them:

$ pkg-config --variable=abi_videodrv xorg-server
9.0
$ pkg-config --variable=abi_xinput xorg-server
12.1

Debian-side: Using virtual packages

Server’s build system

When xorg-server gets built, we use pkg-config’s output to determine the current major. Through substitution variables, we add two virtual packages in the Provides field of the server (for both xserver-xorg-core and xserver-xorg-core-udeb): xorg-input-abi-$x and xorg-video-abi-$y, where $x and $y are the major part of the version queried through pkg-config variables.

To handle ascending compatibility for minors, we maintain in debian/serverminver the minimal version of xserver-xorg-core which is needed. When a minor is bumped, we store the server version in that file. This way, drivers built afterwards will depend on a minimal version of the driver, the last which saw a minor version bump. In other words: they will “depend on the server version they were built against, or a higher/compatible one”.

Both ABI and minimal server version are recorded in two files shipped in xserver-xorg-dev, to be used while building drivers:

  • /usr/share/xserver-xorg/xinputdep

  • /usr/share/xserver-xorg/videodrvdep

Example for xinputdep:

xorg-input-abi-11, xserver-xorg-core (>= 2:1.8.99.904)

To make sure we bump the debian/serverminver when there’s a minor ABI change, there’s a abibumpcheck target (on which clean depends), which extracts input and video ABI from the upstream header, and compares them to the previous ones stored in debian/serverminver, failing and diffing is something changed.

Driver’s control file

Drivers also use substitution variables in their control file, replaced at build time.

# Input driver:
Depends: ${xinpdriver:Depends}, …
Provides: ${xinpdriver:Provides}

# Video driver:
Depends: ${xviddriver:Depends}, …
Provides: ${xviddriver:Provides}

For now, ${xinpdriver:Provides} is always replaced with xorg-driver-input, and ${xviddriver:Provides} is always replaced with xorg-driver-video. Hopefully provided packages will not change, but using substitution variables is cheap, and makes it easy to add tweaks afterwards if needed.

Driver’s build system

To set those variables, we ship a dh_xsf_substvars script in xserver-xorg-dev starting with 2:1.9.4, to be run before dh_gencontrol. It iterates on the packages listed by dh_listpackages (very old debhelper command) and does the following work:

  • It reads variables from the files mentioned above.

  • If a package name ends with -udeb, it replaces xserver-xorg-core with xserver-xorg-core-udeb.

  • If a package name ends with -dbg, it does nothing for this package. Debug packages usually depend strictly on the non-debug packages, which in turn have appropriate dependencies.

  • If a package name starts with xserver-xorg-input-, it appends xinpdriver:Depends=… and xinpdriver:Provides=… to this package’s substvars file.

  • If a package name starts with xserver-xorg-video-, it appends xviddriver:Depends=… and xviddriver:Provides=… to this package’s substvars file.

Why such heuristics? The idea is to avoid getting “unused substitution variable” warning messages while building. And since there’s a clear xserver-xorg-{input,video}-* namespace, we can use that to specify only input-related variables for input drivers, and only video-related variables for video drivers.

To make it easy to compute substvars when using dh, a dh sequence (xsf.pm) is shipped. As of 2:1.9.4-1, it inserts dh_xsf_substvars right before the dh_gencontrol call. Other repetitive tasks could also be automated this way.

Sample driver packaging

The following assumes:

  • The upstream build system is sane enough, which lets us run autoreconf at build time.

  • It is a video driver. For an input driver, replace both xviddriver occurrences with xinpdriver.

Sample debian/control file

Build-Depends:
 debhelper (>= 8),
 dh-autoreconf,
 quilt,
 xserver-xorg-dev (>= 2:1.9.4),
Depends:
 ${shlibs:Depends},
 ${misc:Depends},
 ${xviddriver:Depends},
Provides:
 ${xviddriver:Provides}

Sample debian/rules file

#!/usr/bin/make -f

# Configuration:
#override_dh_auto_configure:
#        dh_auto_configure -- --with-FOO --without-BAR

# Install in debian/tmp to retain control through dh_install:
override_dh_auto_install:
        dh_auto_install --destdir=debian/tmp

# Kill *.la files, and forget no-one:
override_dh_install:
        find debian/tmp -name '*.la' -delete
        dh_install --fail-missing

## Debug package:
#override_dh_strip:
#        dh_strip --dbg-package=xserver-xorg-video-DRIVER-dbg

# That's a plugin, use appropriate warning level:
override_dh_shlibdeps:
        dh_shlibdeps -- --warnings=6

%:
        dh $@ --with quilt,autoreconf,xsf --builddirectory=build/

Some comments:

  • dh_auto_configure: Commented out since there’s usually no specific option to pass when building drivers. Sometimes needed to get a related utility built.

  • dh_auto_install: It behaves differently when operating on a single package (it installs under debian/PACKAGE instead of debian/tmp), so make it use debian/tmp in all cases. This way, dh_install has to be used (see below). That also means that a binary package (e.g. a debug package) can be added without changing this part.

  • dh_install: No point in keeping the .la files. Also, using --fail-missing makes sure every file installed by upstream is installed in some package, or explicitly ignored.

  • dh_strip: Commented out, there’s only a few drivers shipping a debug package.

  • dh_shlibdeps: The comment really says it all.

  • dh: The order is important! We want patching to happen before autoreconfiguring (both quilt and autoreconf insert commands before dh_auto_configure, and after dh_clean). Also, we build out-of-tree. The xsf sequence is explained in the previous part.

If one needs to build several flavours, fbdev’s rules file can be used as an example.

Handling a transition

When a new major version of the server comes up, it can be updated following its README.source. Usually, drivers can be rebuilt using binNMUs. Be sure xorg-server is marked as Installed on all buildds, or set a dep-wait.

On the release team side, a transition page can be asked for, to track fully rebuilt drivers. For the input 12→13 and video 10→11 transitions, the settings are:

  • Affected: .build-depends ~ /xserver-xorg-dev/

  • Good: .depends ~ /xorg-input-abi-13/ | .depends ~ /xorg-video-abi-11/

  • Bad: .depends ~ /xorg-input-abi-12/ | .depends ~ /xorg-video-abi-10/

Staying tuned

Staying informed of driver-related changes can be a bit difficult in the following cases:

  • If one maintains a single driver within the X Strike Force, one might not notice the few mails about drivers in the heavy mail flow on debian-x@.

  • If one maintains a driver outside the X Strike Force, one is probably not subscribed to the mailing list at all.

For those reasons, a mail alias is being set up to gather all maintainers interested in receiving driver-related mails.