Ce billet existe aussi en français

This post is part of a series about how to package a XULRunner application.
See the preamble for the context case.

2.2 Package as deb

2.2.1 Synopsis

Ok, so we have our launcher, and all the files needed for the desktop integration (see chapter 2.1). We will now create a deb package, for Debian based distributions, like Ubuntu.

The main documentation for deb creation is the Debian Policy Manual. And you can find useful too this other doc from Debian and this one from Ubuntu.

I suppose that our app doesn't contain any compiled code, but if you have some, simply compile it before packaging. We will create this deb manually.

We will use debhelper and fakeroot. We have to create some files used by the debian scripts, copy our sources and our desktop files in the right location, then run some scripts.

For that, we need to install debhelper and fakeroot.

on Debian/Ubuntu:

  • apt-get install debhelper fakeroot

On Fedora, unfortunatly debhelper is not yet available in the default repository, but it should be one day, see the bugs #591190, #591389, #642160, and #591332.

On OpenSuse there's a package named 'deb' from openSuse which install it.

On others... let me know ;)

The created deb will install myapp in the /usr/lib/ folder, this is the standard location on Linux.

2.2.2 Debian files

To build our deb, we need to create a debian folder alongside our application, with several files into it used by the debhelper programs.
You can use dh_make to create a such skeleton, but here we will create these files by hand:

    |- samples_chapter_2/
|- myapp/
|- debian/
|- changelog
|- compat
|- control
|- copyright
|- menu
|- postinst
|- myapp.links

The changelog file is described in detail here in the doc, it will contain:

myapp (1.0-1) unstable; urgency=low

* Initial release

-- John Doe <johndoe@example.com> Fri, 26 Nov 2010 10:10:35 +0100

Note: be precise on the formatting of this file, it must be really precise, see the doc.

Note: the date must be in RFC822 format, you can obtain it with date -R in a terminal.

The compat file contains simply the debhelper compatibility, so just 7 .

The control file is the more important one. Here's a sample:

Source: myapp
Section: Utilities
Priority: extra
Maintainer: John Doe <johndoe@example.com>
Build-Depends: debhelper (>= 7)
Standards-Version: 3.7.2
Homepage: <http://example.com/myapp/>

Package: myapp
Architecture: all
Depends: xulrunner (>= 1.9.2) | firefox (>= 3.6)
Description: simple Hello World.
Powered by XULRunner.

Choose a Section from this list.

If your application contains some compiled code, you must remove the line Architecture: all , because its goal is precisely to create a platform independent package. Without this entry, the deb will be specified for the current platform.

If your app requires some other dependencies, add them separated by a comma. If your app contains some compiled code, you can want to use the ${shlibs:Depends} value, when the package will be built, some dependencies will be determined. Example

Depends: xulrunner (>= 1.9.2) | firefox (>= 3.6), ${shlibs:Depends}

The format of the field Description is described in detail in this doc.

The copyright file can contain by example:

This package was debianized by John Doe <johndoe@example.com> on
Sat, 16 Oct 2010 17:55:17 +0200

It was downloaded from <http://example.com/myapp/>

Upstream Author(s):
John Doe <johndoe@example.com>

Copyright:
<Copyright (C) 2010 John Doe>

License:
***** BEGIN LICENSE BLOCK *****
Version: MPL 1.1/GPL 2.0/LGPL 2.1

The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.

The Original Code is MyApp.

The Initial Developer of the Original Code is John Doe.
Portions created by the Initial Developer are Copyright (C) 2010
the Initial Developer. All Rights Reserved.

Contributor(s):
John Doe (johndoe@example.com)

Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.

***** END LICENSE BLOCK *****

The menu file contains:

?package(myapp):needs="X11" section="Applications/Programming"\
title="MyApp" command="/usr/bin/myapp"

Choose a section in this list.

The postinst file is a script launched after the deb installation.  It allows to rebuild the cache of the system icons for example:

#!/bin/sh
# postinst script for myapp
#
# see: dh_installdeb(1)

set -e

# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package

case "$1" in
configure)
# for icons of the app
if [ -x /usr/bin/gtk-update-icon-cache ]; then
gtk-update-icon-cache -f /usr/share/icons/hicolor
fi

# uncomment only if the installed app handle some mime-type
#if [ "$2" == "" ]; then
# if [ -x /usr/bin/update-desktop-database ]; then
# update-desktop-database /usr/share/applications
# fi
#fi
;;

abort-upgrade|abort-remove|abort-deconfigure)
;;

*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac

# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.

#DEBHELPER#

exit 0

Finally, the myapp.links file contains the links to create when the deb will be installed:

/usr/lib/myapp/myapp.sh /usr/bin/myapp

2.2.3 Create the deb

Ok, we have now all the necessary files, we can generate our deb. We have to create a folder named like our app name into the debian folder, and under it copy the files like in the final root system:

    |- debian/
|- myapp/
|- usr
|- lib
|- myapp/
|- share
|- applications/
|- myapp.desktop
|- icons/
|- hicolor/
|- 16x16/
|- apps
|- myapp.png
|- 22x22/
|- apps
|- myapp.png
|- 32x32/
|- apps
|- myapp.png
|- 48x48/
|- apps
|- myapp.png
|- scalable/
|- apps
|- myapp.svg

And we will apply some debhelper scripts.

Here a complete shell script, named build_deb.sh, which create a temporary 'tmp' folder, we copy into it our debian files, our application, and our desktop files, then create the deb:

#!/bin/bash

# exit the script on errors
set -e

TMP_DIR=./tmp

# get the absolute path of our TMP_DIR folder
TMP_DIR=$(readlink -f -- "$TMP_DIR")

# re-create the TMP_DIR folder
rm -rfv "$TMP_DIR"
mkdir -v "$TMP_DIR"

#copy the debian folder into TMP_DIR
cp -rv "./debian" "$TMP_DIR/"

# create into TMP_DIR the folder where copy our app
mkdir -pv "$TMP_DIR/debian/myapp/usr/lib"

# and copy the app
cp -rv "./myapp" "$TMP_DIR/debian/myapp/usr/lib/"

# create the folder for the .desktop file and copy it
mkdir -pv "$TMP_DIR/debian/myapp/usr/share/applications"
cp -v "./data/myapp.desktop" \
"$TMP_DIR/debian/myapp/usr/share/applications/"

# create the folder and copy our icons
mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/16x16/apps"
cp -v "./data/icons/icon16.png" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/16x16/apps/myapp.png"

mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/22x22/apps"
cp -v "./data/icons/icon22.png" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/22x22/apps/myapp.png"

mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/32x32/apps"
cp -v "./data/icons/icon32.png" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/32x32/apps/myapp.png"

mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/48x48/apps"
cp -v "./data/icons/icon48.png" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/48x48/apps/myapp.png"

mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/scalable/apps"
cp -v "./data/icons/icon48.svg" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/scalable/apps/myapp.svg"

cd "$TMP_DIR"

# clean eventual tempory files
find . -type f -name *.*~ -exec rm {} \;

# deb creation
fakeroot dh_link
fakeroot dh_fixperms
fakeroot dh_installdeb
# uncomment the following line if you have some compiled code and use ${shlibs:Depends} in control file
#dh_shlibdeps
fakeroot dh_gencontrol
fakeroot dh_md5sums
fakeroot dh_builddeb

echo "deb created for myapp :)"

To create our deb, in a terminal:

  • cd samples_chapter_2
  • sh ./build_deb.sh

And as result we have finally the file myapp_1.0-1_all.deb in the samples_chapter_2 folder :) .

Nicolas Martin

You can download all the samples of this chapter 2 (Linux) in the samples_chapter_2.tar.gz archive.

The myapp application, from developer.mozilla.org is in the Public Domain.

The icon used is from the Tango Desktop Project, and is in the Public Domain.

All added data, and sample files, of this chapter 2, are in the Public Domain too.