logo Autopackage - Easy Linux Software Installation

Autopackage GNOME Launch Box Tutorial

Building the package

We've prepared the software: made it relocatable, audited its dependencies, relaxed a troublesome one and now we can make the actual autopackage. This bit is the easiest part.

Like most packaging systems, autopackage uses a specfile to describe how to make the final result. To create one, make a directory called "autopackage" in the source tree and generate a template specfile with the makepackage --mkspec >default.apspec.in command. It's an autoconf template: the @VERSION@ field will be expanded from the configure script to specify the software version.

$ mkdir autopackage
$ makepackage --mkspec >autopackage/default.apspec.in

(now modify configure.ac)

$ ./autogen.sh
You can also use our APSPec Generator utility which is a graphical wizard style applications that guides you through this process. See the Tools Download Page for details.

OK, let's customise the specfile. At the top is a [Meta] section. This contains some useful metadata about the package.

[Meta]

[Meta]
RootName: @imendio.com/gnome-launch-box:$SOFTWAREVERSION
DisplayName: Launch Box
ShortName: gnome-launch-box
Maintainer: Richard Hult 
Packager: Mike Hearn 
Summary: Launch Box is a fast way to activate programs, contacts and bookmarks
URL: http://developer.imendio.com/wiki/GNOME_Launch_Box
License: GNU General Public License, Version 2
SoftwareVersion: @VERSION@
PackageVersion: 1
AutopackageTarget: 1.0
# InterfaceVersion: 0.0

Some of the fields should be self explanatory. A few are not, so we will explain them.

RootName

The versioned root name is a unique identifier for your package. Autopackage uses root names to name packages without requiring a central repository. The root name consists of:

  • An @ symbol, followed by a domain name that is owned by the maintainers of the software being packaged. This is used as namespace, so packages that have the same software name won't conflict with each other.
  • It should have at least one backslash (/) and it should not end in a backslash.
  • A software name, followed after the last backslash.

Here are some examples:

  • @gaim.sourceforge.net/gaim:1.4 - correct
  • @www.lilypond.org/lilypond:1.0 - incorrect due to leading www
  • @http://www.lilypond.org/ - incorrect, root names are not URLs so should not have a protocol identifier, it's also missing the version part (after the colon)
  • @lilypond.org/index.html:2.4 - incorrect, root names are not URLs so should not point to web pages
  • @lilypond.org - incorrect, you must have at least one backslash and following subname, and it must end in :VERSION
  • @coolsite.net/projects/project cool:0.99 - incorrect, no spaces or other "weird" characters allowed
  • @mozilla.org/firefox:deerpark - incorrect, software version must be in a form that autopackage can compare against. The parser is pretty flexible, but codenames won't fly.

Normally, selecting a root name is easy. If you are not the maintainer of whatever it is you're packaging, make sure the developers do know that you produced a package and what root name was allocated. If you think somebody may have produced an autopackage of the software before, check in with whoever maintains the software currently to find out what root name they used.

AutopackageTarget
AutopackageTarget identifies the version of autopackage that you are writing it against. This versioning mechanism allows you to choose as and when new features and potentially incompatible changes are made to your package. This is a value of the form X.Y where X and Y are integers. In other words, you cannot require a minimum patchlevel of the autopackage runtime using this mechanism, only a new release in the 1.x series (eg, 1.2, 1.4, 1.6). If a user has autopackage 1.0 and installs a package that requires 1.2 then they will be upgraded. If you don't use the new features, the user won't have to wait while the runtime is upgraded.

Generally, you should accept the default here. When a new major version of autopackage comes out, it will be accompanied by a short migration document. This will cover any issues you need to be aware of such as ways to improve your specfile. Sometimes new features will be free - the change to LZMA compression in autopackage 1.2 is an example of that. At other times, you'll need to change your package to take advantage of them.

InterfaceVersion
The interface version identifies what interface this package exports, if any. An "interface" in this context is anything that another package may rely on. Applications usually don't expose any interfaces, unless they have a plugin system. Libraries on the other hand usually do. Interface versions are covered in the packagers guide in more detail, suffice it to say that you need to decide how to allocate interface versions based on the versioning history of your libraries/plugin API. If you aren't the maintainer, co-ordinate with them to ensure this value makes sense.

In this case, Launch Box does not export any interfaces to other parts of the system (user interfaces don't count!). So we can leave it commented out or delete it.

[BuildPrepare/BuildUnprepare]

Autopackage scripts are shell scripts!

An important thing to know and to remember: all code in the [BuildPrepare], [BuildUnprepare], [Imports], [Prepare], [Install] and [Uninstall] sections are shell script codes! Everything you can do in bash, you can do here too!

These parts of the specfile describe how to compile the program ready for packaging. Because most projects use the GNU build system and are very standardised, we provide two helper APIs, prepareBuild() and unprepareBuild(). prepareBuild takes care of calling configure, make and make install for you, while unprepareBuild handles the cleanup.

If you don't want to use these for whatever reason, the scripts essential task is to create an installed tree in the directory pointed to by $build_root.

Note: the working directory in this section is the folder in which makepackage is invoked. prepareBuild runs make install in such a way that everything is installed to $build_root.

For Launch Box we can leave these sections at the defaults:

[BuildPrepare]
prepareBuild

[BuildUnprepare]
unprepareBuild

[Imports]

Often a programs build system will install more files than it really makes sense to have in a package. For instance, it may install header files or ChangeLogs which are no use to your average user. The [Imports] section lets you choose what files from the build root will be pulled into the package payload itself. The default is to import everything.

Note: the working directory in this section is $build_root! The folder in which makepackage is invoked is referred by $source_dir.

The easiest way to use this section is just to delete what you don't want before the imports call. For Launch Box, we want to import everything everything so we can leave this at the default:

[Imports]
echo '*' | import

[Prepare]

Autopackages install in two stages. First, every package in the dependency chain is prepared. Once all of the packages have succesfully prepared they're installed in sequence. In the Prepare section you should do any checks that could affect whether the install can proceed or not. Dependency checks are the most common thing to put here, but you from autopackage 1.2 onwards you can also uninstall native packages if they conflict with what you're installing (eg, if the user is upgrading an RPM based install of Launch Box to the autopackage)

Because dependency checking (and resolution) is a very common thing to do here, autopackage provides a lot of infrastructure to support it. This revolves around skeleton files. An autopackage works in a similar way to the standard configure script: it uses a library of tests to figure out whether the system has what it needs. Skeleton files are equivalent to the M4 macros autoconf uses, except that they work in a different way.

For each dependency your program has, there must be a skeleton file. If there isn't you'll need to write one. Fortunately, autopackage ships with a large library of skeletons out of the box, and we are happy to accept any others you write. In future it's hoped that projects will install skeleton files much like they install .pc files or headers today. Skeletons are copied into the package itself, and you can put custom skeletons into the autopackage directory along with your specfile.

The purpose of a skeleton file is to map the state of the system to a set of interface versions. The chosen interface versions are arbitrary and up to the skeleton author. Often the mapping will be obvious or intuitive, but sometimes it may not be. Consult the notes section of the relevent skeletons for more information.

The Launch Box prepare script looks like this:

# Dependency checking
require @gtk.org/gtk 2.4
require @gnome.org/libgnomevfs 2.10
require @gnome.org/libgnomeui 2.0
# let's assume for now that if gnome-vfs 2.10 is installed, the rest of gnome 2.10 is also
recommend @gnome.org/evolution/libebook 3

As you can see, autopackage supports both hard dependencies (requirements) and soft dependencies (recommendations). The difference is that while both types will attempt to resolve the dependency, if require fails it'll abort the install. Recommend, on the other hand, never fails. If the user is missing a package that is recommended, the install will continue but at the end, they'll be reminded that installing this package would give them extra functionality.

The number at the end is the interface version. For the GNOME/GTK+ libraries, it's obvious where the number comes from. For libebook it's not obvious. Actually, I had to write a libebook skeleton specifically for GNOME Launch Box, as it wasn't in the autopackage library. Let's see how I did that.

Skeletons

[Meta]
RootName: @gnome.org/evolution/libebook
DisplayName: Evolution Address Book Library
ShortName: libebook
Skeleton-Author: Mike Hearn 
Skeleton-Version: 1

[Notes]
e-d-s versioning in general is weird and messed up, this skeleton may
well be totally inaccurate or wrong.  You have been warned. Different
soname versions are mapped to different major interface versions.

[Test]
INTERFACE_VERSIONS=`testForLib -v libebook-1.2.so`
if [[ "$INTERFACE_VERSIONS" != "" ]]; then
	SOFTWARE_VERSIONS="1.2"
fi

This text should be put in a file called "skeleton.1", in "/usr/share/autopackage/skeletons/@gnome.org/evolution/libebook". It can be put in the project-specific autopackage directory also.

As you can see, it consists of several parts. The first is the familiar Meta section. Packages aren't the only thing that have root names: they also uniquely identify logical interfaces. In this case, we assigned the libebook library the root name @gnome.org/evolution/libebook. We also associated this root name with a display name (which can be localized), and a short name. The display name will be used in the "Checking for ...." messages in the user interface. Finally a bit of metadata about the skeleton itself is provided. Skeletons are versioned too, but this facility is rarely needed and we'll ignore it here.

The Notes section is freeform. Autopackage doesn't care what goes here, so it's useful for communicating to the packager how your skeleton represents the state of the system. In this case, we remark upon the confusing and not so well documented state of libebook versioning: the skeleton is likely to change in future.

The Test section is where the work is done. This code should set two variables, INTERFACE_VERSIONS and SOFTWARE_VERSIONS. INTERFACE_VERSIONS is required but SOFTWARE_VERSIONS is optional - it's used for the requireExact/requireAtLeast functions.

The testForLib function returns the version numbers after the .so extension for the given soname. On my system, this returns "3.1.1" because I have libebook-1.2.so.3.1.1 installed. Whilst technically interface versions have to be precisely two integers, X.Y, autopackage will drop the last component if one is supplied. That's why you can directly feed the results of testForLib into the INTERFACE_VERSIONS variable.

In this case, we simply use the fact that we only detect libraries from API version 1.2 to set SOFTWARE_VERSIONS. A bit of a cop-out, but there you go.

Install

Now we verified that our package could install OK, it's time to actually do it.

You install the files that were imported earlier using the install* APIs. There is one API for each type of file you may be copying. In this case, Launch Box is very simple and only has two file types:

[Install]
installExe bin/*
installData share/lb

As you can see, we match up the API to the type of file. In future, writing [Install] sections will probably be automated. For now you must do it yourself. There is a file type to API cheat-sheet available in the developer quickstart document.

For files that don't have any specific API, we can use copyFiles. We use these functions instead of regular "cp" because they take care of many messy details for us. For instance, we don't have to specify the destination because autopackage will work that out for us based on the users chosen prefix, defaults, distribution layout and file type. The APIs may also perform various transformations upon the files for things like menu items and so on to work around differences in distributions.

Final steps

The [Uninstall] section can be left as-is. Now we just have to turn our completed specfile and software into a tasty package the user can grab and install with ease. This is the job of makepackage.

To build our package, we simply run the makepackage command in the root of our source directory. The autopackage/default.apspec file will automatically be used. makepackage knows to regenerate the specfile from the autoconf template if one exists, so you don't have to do this yourself when changing the spec. Before you run makepackage, make sure to do a "make clean" to clear out any previous builds you may have there. It's important that a clean build is done because otherwise apbuild (the binary portability tool) will not be fully effective.

If we get any warnings at the end, we need to go back and fix them. Otherwise, our package is ready to go! All we need to do is test it and we're good.

Wrapping up

There are a couple of details here I chose to ignore. The first is that GNOME Launch Box is fairly incomplete as a program - for instance, there's no menu entry. Autopackage only shows the user packages that provide menu entries in the graphical uninstaller, so the user not only has no graphical way to start the program, but also no way to uninstall it if they get bored. Fixing this is easy, we just need to provide a .desktop file and icon for it. Autopackage provides the "makeicons" script in apbuild to make integrating SVG icons into your softwares build system easier.

The second is C++ support. Launch Box is written in C so we can get away with ignoring this for now. C++ support is changing radically in autopackage 1.2, which isn't out yet, so it makes sense to gloss over this until things settle down. A new tutorial will cover what to do for C++ apps when the support is ready. For now, remember the basic rule: it's OK to distribute C++ apps as long as they don't link against any C++ libraries. For instance, AbiWord is OK because it "stands alone" and does not use any C++ libraries. Inkscape is also OK once you statically link the GTKmm bindings. But KDE/Qt apps aren't OK, at least, not yet.

Autopackage GNOME Launch Box Tutorial


p