Page Body
Packaging Java with Javatools
I have just uploaded javatools 0.5 to unstable and it is currently waiting in NEW. Anyone wishing to try it out earlier can find source and packages (it's arch: all) at http://www.srcf.ucam.org/~mjj29/javatools/.
Javatools replaces the existing jarwrapper package and also contains programs to help packagers in creating packages for Java programs and libraries.
Packaging tools
The javahelper package consists of several small programs which make packaging Java programs and libraries easier. They are generally designed to work in the same fashion as the debhelper programs, but start with the jh_ prefix.
All of the programs have their command line arguments documented in manpages.
jh_build
Many Java programs and libraries are distributed without sane build systems. jh_build provides a simple interface for building Java source code into Jars, including setting the appropriate entries in the manifest.
In almost all cases all that needs to be done to call jh_build is to set JAVA_HOME and CLASSPATH and then call jh_build with the name of the jar and the directory containing the source.
JAVA_HOME=/usr/lib/jvm/java-gcj CLASSPATH=/usr/share/java/esd.jar:/usr/share/java/jsch.jar jh_build weirdx.jar src
This command will compile all the Java files under src, set the classpath in the manifest and build it all into weirdx.jar.
A couple of other options are worth mentioning. If this jar contains an application rather than a library then the -m or --main option can be used to set the Main-Class attribute in the manifest which will allow the resulting jar file to be be executed
jh_build also provides a --clean parameter which should be called in the clean target of debian/rules.
jh_libs
For library packages Debian Java policy currently requires that the libraries be installed to /usr/share/java in a versioned format and with an unversioned symlink. jh_libs will take a jar and correctly install it.
As with debhelper programs, this can either take a jar as a parameter, or read a list of jars from a file in the Debian directory. It also follows the -p, -i and -s semantics of debhelper for selecting which packages to install the jar to. When operating on a package, jh_libs will read the list of library jars from debian/package.jlibs or debian/jlibs.
The jlibs file is a list of jars to install, one per line, and works exactly the same as listing them on the command line. Each jar is installed to debian/package/usr/share/java/ in the appropriate versioned and unversioned forms.
jh_depends
jh_depends works like dpkg-shlibdeps, but for jar files. For each jar in the package it takes the jars on which it depends and finds the packages to which they belong. These are included in the debhelper substvars as ${java:Depends}. The control file can then just list that variable which is filled in automatically.
This is done by reading the Class-Path attribute from the manifest of each jar. Jar files should include this attribute to prevent applications which use them from needing a full recursive classpath in their startup scripts and to prevent unneccessary transitions when the library changes its dependencies. If the package is not built with jh_build and the upstream build system doesn't set it correctly then jh_manifest can be used to fix this.
If the application uses executable jars (see Runtime support below) then jh_depends will also add the appropriate depends on jarwrapper and the correct Java runtime.
jh_manifest
Many upstream build systems do not set the Class-Path attribute in the jars they create. This leads to several unwanted problems, such as expanding the classpath which applications have to use and introducing unneccessary transitions. They also may not set the Main-Class attribute. Both of these are required for running jars with the -jar parameter.
jh_manifest can fix the manifest files of jars. It can either read from a manifest file in the Debian directory or run in a mode which updates all the jars with the CLASSPATH environment variable.
The manifest files can either be debian/package.manifest or debian/manifest. The format of this file is a list of jars and indented below each one a list of manifest elements to set:
usr/share/weirdx/weirdx.jar: Main-Class: com.jcraft.weirdx.WeirdX Debian-Java-Home: /usr/lib/jvm/java-gcj
jh_exec
The Runtime support section below describes running executable jars directly. jh_exec will scan package directories for jars in the paths, or symlinks to jar from the paths, and ensure that they have been set executable if necessary.
jh_makepkg
jh_makepkg will create template Debian packages for Java programs and libraries similar to dh-make. It should be run in the source directory and it will create the orig.tar.gz and most of the files in the Debian directory, which need only small changes neccessary to build the package.
java-propose-classpath
Some upstreams have complicated classpaths which may not be obvious to the packager when using jh_manifest to set the Class-Path attribute. java-propose-classpath will unpack a jar and look at the symbols imported to the class files, then scan all the jars in /usr/share/java. This shouldn't be run in the build since it is slow, and there may be ambiguities that the packager must resolve. It is still very useful for the packager as most of the time it will get it right automatically.
Runtime support
Javatools also provides some runtime support. Unlike compiled programs, or purely interpreted programs with hash-bang lines, Java programs cannot be directly executed. Many upstreams expect them to be run using java -jar jarname or java classname. This is not generally acceptible in systems which expect to just be able to run the command or launch it from a menu. As a result, many packagers are writing wrapper scripts which just call java with the correct classpath, jar and main class.
jarwrapper
There is an alternative to wrapper scripts, however. The binfmt_misc kernel module allows the kernel to call out to a program in userspace to execute specific types of file. jarwrapper registers itself as a handler for executable jars. This is done by reading values from the manifest file.
In order for executable jars to work the following attributes must or may be defined in the manifest. These attributes can be set using jh_build and jh_manifest.
- Main-Class: The name of the class to be run when the application starts. (REQUIRED)
- Class-Path: The path to all the jar files on which this jar depends. (REQUIRED unless empty)
- Debian-Java-Home: A Debian-specific property if this application depends on a specific runtime. Specify the path to the runtime which should be used. (OPTIONAL)
- Debian-Java-Parameters: A Debian-specific property if this application needs extra options to the JVM. (OPTIONAL)
Putting it together
This section shows the debian packaging generated by jh_makepkg for an application and a library using jh_build.
Sample Library Packaging
debian/control
Source: jsch Section: libs Priority: optional Maintainer: Matthew Johnson <mjj29@debian.org> Build-Depends: debhelper (>= 5), javahelper, java-gcj-compat-dev, libzlib-java Standards-Version: 3.7.3 Homepage: http://www.jcraft.com/jsch/ Package: libjsch-java Architecture: all Depends: ${java:Depends}, ${misc:Depends} Description: Java secure channel JSch is a pure Java implementation of SSH2. JSch allows you to connect to an sshd server and use port forwarding, X11 forwarding, file transfer, etc., and you can integrate its functionality into your own Java programs. JSch is licensed under a BSD style license.
debian/rules
#!/usr/bin/make -f export JAVA_HOME=/usr/lib/jvm/java-gcj export CLASSPATH=/usr/share/java/zlib.jar build: build-stamp build-stamp: dh_testdir jh_build jsch.jar src touch $@ clean: dh_testdir dh_testroot jh_build --clean dh_clean rm -f build-stamp jsch.jar install: build dh_testdir dh_testroot dh_clean -k dh_installdirs binary-arch: build install # Java packages are arch: all, nothing to do here binary-indep: build install # Create the package here dh_testdir dh_testroot dh_clean -k dh_install -i dh_installdocs -i dh_installchangelogs -i dh_javadoc -i --sourcedir=src jh_libs -i jh_depends -i dh_compress -i dh_fixperms -i dh_installdeb -i dh_gencontrol -i dh_md5sums -i dh_builddeb -i binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install
debian/libjsch-java.jlibs
jsch.jar
Sample Application Packaging
debian/control
Source: salliere Section: misc Priority: optional Maintainer: Matthew Johnson <mjj29@debian.org> Build-Depends: debhelper (>= 5), java-gcj-compat-dev, fastjar, libmatthew-debug-java, libcsv-java, libitext-java, javahelper Standards-Version: 3.7.3 Package: salliere Architecture: all Depends: ${java:Depends}, ${misc:Depends} Description: Short Description Long Description
debian/rules
#!/usr/bin/make -f export JAVA_HOME=/usr/lib/jvm/java-gcj export CLASSPATH=/usr/share/java/csv.jar:/usr/share/java/debug-disable.jar:/usr/share/java/itext.jar build: build-stamp build-stamp: dh_testdir # Build the package jh_build salliere.jar src touch $@ clean: dh_testdir dh_testroot jh_build --clean dh_clean rm -f build-stamp salliere.jar install: build dh_testdir dh_testroot dh_clean -k dh_installdirs binary-arch: build install # Java packages are arch: all, nothing to do here binary-indep: build install # Create the package here dh_testdir dh_testroot dh_clean -k dh_install -i dh_installdocs -i dh_installchangelogs -i jh_manifest -i dh_link -i jh_exec -i jh_depends -i dh_compress -i dh_fixperms -i dh_installdeb -i dh_gencontrol -i dh_md5sums -i dh_builddeb -i binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install
debian/salliere.install
salliere.jar usr/share/salliere
debian/salliere.links
usr/share/salliere/salliere.jar usr/bin