Packaging a libGDX project for Ubuntu

Introduction

We have already seen how to create an installable .deb package. However, to make it Ubuntu we need a source package that actually builds on the Launchpad server farm. This is not hard, but in practice you’ll probably be tinkering for hours before you end up with a package that Launchpad considers valid.

A libGDX project

We start from an Android Studio project named Caved Fizzer, a simple (and rather annoying, or challenging…) game that we use for demonstration purposes on this site. Make sure to have a Desktop Application configuration. If you don’t, go to Edit Configurations and add one. The main class is the launcher class of the ‘desktop’ project, e.g. de.nitri.cavefizzer.desktop.DesktopLauncher . The working directory is the assets directory of the Android project, e.g. /Users/helfrich/AndroidStudioProjects/CaveFizzer/android/assets , and the classpath must be set to ‘desktop’.

Copy what you need

We create a directory ‘deb’ in our home directory that we’ll use to debianize the Android Studio project. Create a subdirectory with the same name as the project, e.g. deb/CaveFizzer . Now we’ll copy what we need there, that is:

– the top level build.gradle
– settings.gradle
– the ‘core’ project
– the ‘desktop’ project
– the assets directory from the ‘android’ project

The Debian files

In a subdirectory ‘debian’ we need some files, most of which we have seen before (dh_make can generate their prototypes). I won’t discuss them in detail as they are described here: http://packaging.ubuntu.com/html/debian-dir-overview.html .

Note that the control has two paragraphs separated by a blank line: one for the source and one for the binary package. Order matters here. Architecture should be set to ‘any’ as it is targeted on the Launchpad build servers. In order to build a debianized Java package we depend on quilt, javahelper, debhelper, gradle, groovy and default-jdk. Here’s an example:

control:

Source: cavefizzer
Section: games
Priority: optional
Maintainer: Serge Helfrich 
Build-Depends: quilt, javahelper, debhelper (>= 9), gradle, groovy (>= 1.8.0), default-jdk
Homepage: http://pygmalion.nitri.de

Description: How deep can you penetrate our cave system?
 Meet the Fizzer in his exploration of the underground world.
 * Travel as far as you can.
 * Do not hit the rocks.
 * Impress your friends on Google Play Games.
Depends: openjdk-8-jre | openjdk-7-jre | openjdk-6-jre | oracle-java8-installer | oracle-java7-installer | oracle-java6-installer, jarwrapper
Package: cavefizzer
Architecture: any

Patches and changes are managed by Quilt. the source/format file should contain: 3.0 (quilt).

source/format:

3.0 (quilt)

The rules file is nothing but a makefile. Let’s simply start our Gradle build from there. The build process expects some targets, like ‘clean’. We can start with something quick and dirty like this:

rules:

#!/usr/bin/make -f

GRADLE_FLAGS := --offline --stacktrace --refresh-dependencies --gradle-user-home .gradlehome/

%:
	dh $@ --with javahelper,quilt

override_dh_auto_build:
	dh_clean

	gradle desktop:dist $(GRADLE_FLAGS)

	rm -rf .gradle/ .gradlehome/

	mv desktop/build/libs/desktop-1.0.jar desktop/build/libs/cavefizzer.jar 
	dh_installdirs

override_dh_auto_clean:
	dh_auto_clean
	gradle clean $(GRADLE_FLAGS)

	rm -rf .gradle/ .gradlehome/

clean:
	dh_clean
	gradle clean $(GRADLE_FLAGS)
	rm -rf .gradle/ .gradlehome/

The resulting jar lives in the desktop project. We simply move it to where we want it. On Launchpad we have to build off line, hence the –offline flag. So we’ll also need to have the libGDX jars available and package them. Add the binaries to source/include-binaries in the debian directory, e.g:

include-binaries:

libs/gdx-sources.jar
libs/gdx-backend-lwjgl-natives.jar
libs/gdx.jar
libs/gdx-freetype-natives.jar
libs/gdx-natives.jar
libs/gdx-freetype.jar
libs/gdx-tools.jar
libs/gdx-backend-lwjgl.jar

Extract the libraries you need from the libGDX download and move them to libs.

The ‘install’ file specifies where packaged file should go on package installation. The first path is relative to the project root, the second path is relative to the system root.

cavefizzer.install:

desktop/build/libs/cavefizzer.jar usr/games/cavefizzer
debian/cavefizzericon.svg usr/share/cavefizzer
debian/cavefizzer.desktop usr/share/applications

Modify the Gradle build

In settings.gradle remove all projects except ‘core’ and ‘desktop’. Also remove all sections for unneeded projects in build.gradle. Online repositories cannot be reached from the Launchpad build environment so make sure to have everything available locally.

build.gradle:

allprojects {
    version = '1.0'
    ext {
        appName = 'cave-fizzer'
        gdxVersion = '1.3.1'
    }
}

project(":desktop") {
    apply plugin: "java"

    sourceCompatibility = 1.7
    targetCompatibility = 1.7

    dependencies {
        compile project(":core")
        compile fileTree(dir: '../libs', include: '*.jar')
    }
}

project(":core") {
    apply plugin: "java"

    dependencies {
        compile fileTree(dir: '../libs', include: '*.jar')
    }
}

Put it under version control

Launchpad uses the bazaar version control system, which is sort of similar to git. Here’s how it works: http://doc.bazaar.canonical.com/latest/en/mini-tutorial/

Put everything you need under version control, including the build scripts, the project sources, the library jars and the debian directory. Exclude what does not need to be included, like intermediate builds. Use ‘bzr add’ to include files and directories. Use ‘bzr remove’ to exclude what has been unintentionally included, e.g. ‘bzr remove core/build’.

Be sure to commit changes before a new build.

Create an upstream tar

Well, there is some discussion around this file. It contains all original sources used to build the actual package. I simply keep it in sync with my source trees. The version number in the file name must correspond to the version number in debian/changelog. It is located one directory level higher than the project, so ${HOME}/deb in this example.

tar czvfh ../cavefizzer_0.1.3.orig.tar.gz * --exclude='debian' --exclude='build/*' --exclude='build.~*'

Build a package

Now follow the steps described here closely, including the preparations to create a signed package: http://packaging.ubuntu.com/html/packaging-new-software.html You will get errors. The output will usually contain useful error messages. Look for them and fix the problems.

Some imported building steps are:

– Create a build area and build an unsigned .deb package:

bzr builddeb -- -us -uc

– Build a signed and distributable source package in the build area:

bzr builddeb -S
cd ../build-area
pbuilder-dist trusty build cavefizzer_0.1.3-0ubuntu1.dsc

Push to Launchpad

When all of the above works you can upload to your PPA on Launchpad. Use the *source.changes file for that:

dput ppa:<lp-username>/<ppa-name> cavefizzer_0.1.3-0ubuntu1_source.changes

If there still is a problem you’ll get the build log e-mailed to you, containing everything that went right and wrong on the build server. Fix the errors and try again.

Finally Launchpad will build the binary packages for all supported architectures.