openSUSE Build System: Building DEB Packages

Last time around we built packages for siproxd for Fedora and openSUSE. This time we'll look at how to create a deb package for Ubuntu using OBS. I'll assume you have some familiarity with creating deb files already. For information on creating deb files, see the Debian New Maintainers' Guide.

When creating deb packages with OBS it appears to be common practice to keep the rules and control files separate and tar.gz the other files from the Debian directory. You also need to have a partial dsc file in order for OBS to build your package. The Build-Depends line in your dsc file will direct OBS to install all the deb files that a system needs in order to build your deb package. The Files section of the dsc file is not used by OBS and can be trimmed off to avoid having stale and misleading information around.

If you can use the same files for building on all Debian distributions then you will have debian.control, debian.dsc, debian.rules and debian.tar.gz attached to the project. If a particular version of derivative of Debian requires different build instructions, you can create distribution specific versions of these files by including the distribution name and version as a postfix in the filename. For example, instead of debian.dsc you might have siproxd-xUbuntu_9.04.dsc and siproxd-Debian_Etch.dsc.

I found the simplest method to package files for deb based distributions on an rpm based distribution was to install Ubuntu into a virtual machine. This both avoids the hassles of installing the deb bootstrapping code on a Fedora machine and also gives you the ability to roll packages and debug your control and rules files if need be before importing the information into OBS.

Shown in below are the commands to generate the various files required to build a deb package with OBS. These commands are run from a virtual machine running Ubuntu 9.04. First, dh-make and a few other obvious build requirements are installed. Invoking dh_make does most of the work for us, but as you can see there are still a few minor tweaks needed.

Running dh_make does not fill in the package description in debian/control. The first attempt to build the package fails because libosip2 development headers were not installed. With the osip2 packages installed, everything seems to work well, but the plugins fail to compile. This is due to an LDFLAG that dh_make has forced into the build process. Editing debian/rules and changing the LDFLAGS line to not include this option allows the compilation to complete. At this stage you have built a deb on the local machine and can then move the build machinery over to OBS to have it build packages now and in the future.

# apt-get install dh-make autotools-dev

# mkdir /tmp/PKG
# cd    /tmp/PKG
# cp .../siproxd-0.7.1.tar.gz .
# tar xzf siproxd-0.7.1.tar.gz
# cd siproxd-0.7.1
# dh_make -e myemail@example.com -f ../siproxd-0.7.1.tar.gz 
Type of package: single binary, multiple binary, 
  library, kernel module or cdbs?
 [s/m/l/k/b] s
...
# vi debian/control
modify description
# dpkg-buildpackage 
...
checking for osip_init in -losip2... no
*** ERROR: libosip2 is required!   Maybe you need to use --with-libosip-prefix ?
make: *** [config.status] Error 1

# apt-get install libosip2-dev
# dpkg-buildpackage
...
/tmp/PKG/siproxd-0.7.1/src/plugin_demo.c:74: undefined reference to `configuration'
/tmp/PKG/siproxd-0.7.1/src/plugin_demo.c:74: undefined reference to `read_config'
/tmp/PKG/siproxd-0.7.1/src/plugin_demo.c:81: undefined reference to `log_info'
/tmp/PKG/siproxd-0.7.1/src/plugin_demo.c:77: undefined reference to `log_error'
collect2: ld returned 1 exit status
make[3]: *** [plugin_demo.la] Error 1

# vi debian/rules
...
./configure ... LDFLAGS="-Wl,-z,defs"
./configure ... LDFLAGS=""
...

# dpkg-buildpackage
# ls -l ../*deb ../*dsc
-rw-r--...root ... 120K .../siproxd_0.7.1-1_amd64.deb
-rw-r--...root ...  748 .../siproxd_0.7.1-1.dsc

# mv debian/rules debian.rules
# mv debian/control debian.control
# rm -rf debian/siproxd
# tar czf debian.tar.gz debian
# mkdir -p /tmp/DEB//siproxd
# cp debian.* /tmp/DEB//siproxd
# cp ../*dsc /tmp/DEB//siproxd/debian.dsc
# cp ../*deb /tmp/DEB//siproxd

The dsc file has to be modified to include more packages in the Build-Depends clause so that OBS installs all the deb packages needed to build siproxd. The information from the "Files:" to the end of file can be deleted as OBS does not use this and the checksums are likely to become out of date with subsequent releases. The updated dsc file is shown in below.

Format: 1.0
Source: siproxd
Binary: siproxd
Architecture: any
Version: 0.7.1-1
Maintainer: root <bah@example.com>
Homepage: <insert the upstream URL, if relevant>
Standards-Version: 3.8.0
Build-Depends: debhelper (>= 7), autotools-dev

The commands to commit the new debian files and kick off the build are shown below.

$ pwd
.../obs-checkout/home:monkeyiq:network/Siproxd
$ cp /tmp/DEB//siproxd/debian.*
$ osc add debian.*
A    debian.control
A    debian.dsc
A    debian.rules
A    debian.tar.gz
$ osc commit
Sending        debian.control
Sending        debian.rules
Sending        debian.tar.gz
Sending        debian.dsc
Sending        siproxd.spec

The build will fail because we have not mentioned that the libosip2-dev package is a build dependency. Adding libosip2-dev to debian.control will fail with the following message because OBS did not install the dev package for us.

if libosip2-dev dep added only to debian.control:
    dpkg-buildpackage: host architecture i386
    dpkg-checkbuilddeps: Unmet build dependencies: libosip2-dev
    dpkg-buildpackage: warning: Build dependencies/conflicts unsatisfied; aborting.

You have to add the dependency to the dsc file for OBS to pick it up. Modifying the Build-Depends as shown below will cause OBS to attempt to install libosip2-dev before building.

# vi debian.dsc
...
Build-Depends: debhelper (>= 7), autotools-dev, gcc, libosip2-dev

I say that OBS will to attempt to install libosip2-dev because in fact libosip2-dev is in Universe and thus is not available to the xUbuntu_9.04 OBS build target. So the Ubuntu build will then fail with "expansion error: nothing provides libosip2-dev".

If you return to your network project, click "Add Repository" and select the advanced options, you'll notice that there is Ubuntu:9.04:Multiverse/standard. This option does not help however because it still does not include the libosip2-dev package from Universe.

The quickest solution to this is to import libosip2 from universe into a subproject in OBS, for example, Ubuntu_9.04Universe, and link the Ubuntu904universe repository to the Ubuntu 9.04 repository for projects you are maintaining. The subproject Ubuntu_9.14Universe should only have Ubuntu 9.04 enabled as a build target because we are using that subproject only to build universe dependencies for that distribution and version. When somebody installs siproxd from your OBS repository, libosip will be brought in from the real Ubuntu Universe repository.

So, taking things one step at a time. First create a new subproject called Ubuntu_9.04Universe. OBS will switch to that subproject automatically. Then add the repository for Ubuntu 9.04 to the Ubuntu_9.04Universe subproject. Still in the Ubuntu_9.04Universe subproject, create a package called libosip2 and directly import the orig.tar.gz, diff.gz and dsc file from the Universe repository. OBS will then rebuild that package against its own Ubuntu 9.04 repository and create deb files for you.

Now that your own Ubuntu_9.04Universe project includes libosip2-dev deb files, you have to link that subproject to the Ubuntu 9.04 repository in your home:network project. This way, when you build siproxd from your home:network project, it will look at both the Ubuntu 9.04 repository and your Ubuntu_9.04Universe to try to find the deb files needed to build. Because you have libosip2-dev in your Ubuntu_9.04Universe project everything will be found and the build of siproxd will complete.

The command shown below will link the Ubuntu_9.04Universe subproject to the Ubuntu 9.04 repository of the home:network project. From then on packages building for Ubuntu 9.04 in the home:network subproject can happily use "Build-Depends: ... libosip2-dev" and the osip2 dependencies will be pulled in properly. Note that once you link things together, you should not have to trigger a rebuild of siproxd, OBS should work out that it can now build that package and do so automatically.

$ osc meta -e prj home:monkeyiq:network
...
  <repository name="xUbuntu_9.04">
    <path project="Ubuntu:9.04" repository="standard"/>
    <path project="home:monkeyiq:network:Ubuntu_9.04Universe" repository="xUbuntu_9.04"/>
    <arch>x86_64</arch>
    <arch>i586</arch>
  </repository>
...

Traps for the Young Players

For distributions like Fedora, only the main release has been imported into OBS, the updates are not tracked. Of course, a package built against a system library from the release version of Fedora 10 should install on a Fedora 10 system which has all updates applied. But there are some corner cases, for example, libraries which were introduced on the Fedora updates which were not originally part of the release.

A quick way to get around this is to Create a Fedora10Updates subproject and import the sources from the Fedora updates source rpm files taken from Fedora 10 updates. Only enable Fedora 10 for this subproject because its purpose is to rebuild Fedora 10 rpm files so that you can use them to build software targeted at a "Fedora 10 with updates" desktop machine. Linking the project needs a line similar to the one shown below, much like the technique used for Ubuntu universe.

$ osc meta -e prj home:monkeyiq:network
...
<path project="home:monkeyiq:Fedora10Updates" repository="Fedora_10"/>

At the moment the ability to have OBS strip debug information into a separate package is not implemented as an option in the OBS interface. To get around this you should explicitly include %debug_package after your %description so that rpm will build a separate debug package.

Wrap Up

As a fire test of OBS I decided to build packages for libferris for Ubuntu, openSUSE and Fedora. Libferris is both a reasonable sized code base and also has optional support for may third party libraries. The later point makes it a good test for any build system. Although there were some edge cases that were brought up by packaging a large project like this the OBS was up to the task and was also reasonably easy to learn to use along the way.

The openSUSE Build System can be very handy for maintaining a repository of personally built packages so you can easily push new custom package updates onto machines. There are some rough edges when building for Fedora or Ubuntu because the updates and universe repositories are not currently tracked by an OBS project for you. The ability of OBS to trigger rebuilds automatically for you when you make commits can make building a new version of an existing OBS project tree fairly painless.

0