Gentoo Java Packaging Guide

Karl Trygve Kalleberg  Author
Joshua Nichols  Author
Petteri Räty  Author

Updated January 18, 2008

1.  Background

Before going into details of how Java is handled on Gentoo, it is worthwhile to take a few moments to discuss current trends in the Java programming world.

Java Build Systems

There are a few build systems commonly used for Java projects. Apache's ant (Another Neat Tool) is by far the most common. It is a task oriented system. This means that you give Ant instructions on what tasks to perform and how to perform them to build your project. For example, compile these source files using this class path, create a jar of these classes, and so on. It is fairly easy to get up and running with Ant. Unfortunately, it leaves a lot of room for variation, so Ant scripts are terribly inconsistent from one project to the next.

Maven is another Apache project which has been gaining popularity. In contrast to ant, it is a project based system. This means that you give maven information about your project, and once that's established, you can do many things without any further configuration. For example, you tell maven your project's name and where your source is, and you can then tell maven "Hey maven, make me a jar and some javadocs too!" Another feature of maven is its ability take care of making a project's dependencies available by downloading them from mirrors.

You can also find a number of packages using the classic combination of autoconf and automake. They will mostly be found on projects that interact with existing C and C++ libraries. Unfortunately, automake and autoconf are used mostly dealing with the non-Java bits, leaving the Java bits wedged where it can fit.

Lastly, you may find custom scripts which will attempt to run javac, jar, and javadoc itself, or it may just be a wrapper for ant to properly prepare the build environment.

Bundled Dependencies

One of the features of Java has always been "compile once, run everywhere." A consequence of this is that Java developers traditionally bundle all library dependencies with their project's distribution. While this might be convenient for the end-user, it rapidly becomes problematic from a packager's point of view.

For example, project A depends on C, and project B depends on C, and you have project A and B installed, then you'd have two copies of C installed to support it. And if there's new release of C with a bug or security fix , you would want both A and B to take advantage of it.

2.  Java on Gentoo

This section will give you more insight into how Gentoo handles Java. You should be familiar with the Java User Guide before proceeding.

Virtual Machines (VMs)

As discussed in the User Guide, there are several VMs available from portage.

Testing all packages to ensure they build and run with every VM is a huge undertaking, and there simply are not enough resources to guarantee every package will build and run with every VM.

We now maintain a list of "supported virtual machines" for each architecture. These are the VMs we will test the packages against before committing changes to portage. When you emerge a package, it will by default try to use the best "supported virtual machine."

Of course, Gentoo and Linux in general are about choice, so if you prefer a different VM over the "supported virtual machines", you can easily use that VM instead. However, you should also know that bugs reported with one of the non-"supported virtual machine" will get a low priority if it isn't present using a "supported virtual machine".

Configuring which VM to Use

You can choose which VM to use on a per-user basis, and which VM to use for the system (ie when running things as root). Both of these are configured using java-config.

A user's current VM is represented by a symlink located at ~/.gentoo/java-config-2/current-user-vm. This symlink points to the JAVA_HOME of the chosen VM. Similarly, the system VM is represented by a symlink at /etc/java-config-2/current-system-vm.

The current VM can also be changed on the fly. This can be accomplished setting the environment GENTOO_VM to contain the name of a VM that java-config knows about.

Java Tools

The traditional Java tools, ie, java, javac, javadoc, etc, are all located in /usr/bin. They are actually all symlinks to the run-java-tool script. This script will call the appropriate tool, depending on how the script is invoked, from the current VM. GENTOO_VM is first checked, then the user VM, and lastly the system VM.

Build-time VM Switching

As outlined in the User Guide, and mentioned briefly earlier, the VM will switch at build time to accommodate the needs of the package. The VM to use is first determined by JAVA_PKG_FORCE_VM, then /etc/java-config-2/build/jdk.conf, and lastly the system VM.

Bytecode Compatibility

The default behavior of javac is to compile bytecode that will compatible with the current VM version and higher (ie forward compatible). This becomes particularly problematic when trying to use a lower versioned VM. For example, source compiled with 1.4 will be compatible with 1.4 and 1.5, and source compiled with 1.5 will only be compatible with 1.5. This makes it particularly difficult to revert to an earlier VM.

It is possible to specify which VM to compile for to provide the best compatibility.

At build time, the DEPEND and RDEPEND will determine what VM to compile for based on virtual/jdk and virtual/jre. Additionally, this can be controlled by the environment variables JAVA_PKG_WANT_SOURCE and JAVA_PKG_WANT_TARGET.

There is a wrapper for javac, ejavac, which will use the appropriate VM's javac, and then specify the appropriate -target and -source. For projects that use ant, the build.xml can be translated to specify the appropriate -target and -source.

3.  Gentoo Java Packaging Policy

In addition to other Gentoo policies, there are a few unique to Java packages, or that need special attention.

Why build from source?

We should strive to only accept ebuilds that build from source code. For reasons why, please refer to Why Build From Source.

Filesystem Layout

In general, the directory policies are handled for you by the helper functions in the java-utils-2 eclass.

These functions adhere to the following path name conventions:

Slotting

Libraries should be slotted according to the API they provide. If two version have the same API, or if a new version is fully compatible with the previous version, then they should be in the same SLOT.

Java libraries have a tendency to sometimes break API and ABI between minor revisions, ie from 2.1.1 to 2.1.2. As a result, it is necessary to slot early, and slot often.

For applications, it is mostly sufficient to keep only the latest version. If the application comes in series, such as Eclipse, we want to keep the latest revision in each series. Very old series may eventually be dropped completely.

Dependencies

Packages should not use bundled jars. Instead, they should make use of jars from already installed packages.

When depending on a package, take care that you depend on a sufficiently recent version, and explicitly ensure at building time that the providing package gives you the correct interface, i.e. the correct SLOT.

4.  Writing the ebuild

General Guidelines

In addition to standard Gentoo ebuild guidelines, there are a number specific for Java packages:

USE flags

If a manual or other extensive documentation is available, it should be installed using the doc USE flag. If the build system can, you should build javadocs also using the doc USE flag. If it does not, you should consider patching it to do so, and provide the patch upstream. HTML documentation should be installed using dohtml and javadocs using java-pkg_dojavadoc.

If the program provides examples, in the form of source code or some other format, and you think they may be worthwhile for some users to have, install them optionally with the examples use flag using the java-pkg_doexamples function.

If you want to go all the way, add the source USE flag that installs the complete source code as a .zip file. Use java-pkg_dosrc for this purpose. This allows IDEs such as Eclipse and NetBeans to do complete source-level debugging. You will need to also DEPEND="source? ( app-arch/zip )" or add JAVA_PKG_IUSE="source" before inherit. Using JAVA_PKG_IUSE means that we can remove the app-arch/zip requirement in the future and use for example jar provided by virtual/jdk.

If your package comes with unit tests, you can enable these using the test FEATURE, in src_test. If you need extra dependencies for the testing you can pull these in with the test useflag (for example dev-java/junit). We will no longer use the junit use flag for this.

Typical Examples

Without further ado, here are a few examples.

Code Listing 4.1: Example: Pure java package


EAPI="2"
JAVA_PKG_IUSE="doc examples source"

inherit eutils java-pkg-2 java-ant-2

DESCRIPTION="Fictional example ebuild."
HOMEPAGE="http://www.gentoo.org/"
SRC_URI="mirror://gentoo/${P}-src.tar.gz"

LICENSE="Apache-2.0"
SLOT="0"
KEYWORDS="~x86 ~sparc ~ppc ~amd64 ppc64"
IUSE=""

COMMON_DEP="
        dev-java/xerces:2
        >=dev-java/log4j-1.2.8:0"

RDEPEND=">=virtual/jre-1.4
        ${COMMON_DEP}"

DEPEND=">=virtual/jdk-1.4
        ${COMMON_DEP}"

S=${WORKDIR}/${P}-src

java_prepare() {
        cd "${S}/lib"
        rm -v *.jar || die

        java-pkg_jar-from xerces-2
        java-pkg_jar-from log4j log4j.jar log4j-1.2.8.jar
}

src_install() {
        java-pkg_newjar target/${P}-dev.jar ${PN}.jar

        use doc && java-pkg_dojavadoc dist/api
        use source && java-pkg_dosrc src/java/org
        use examples && java-pkg_doexamples src/java/examples
}

Code Listing 4.2: Example: Optional java support


EAPI="2"

inherit eutils java-pkg-opt-2

DESCRIPTION="Fictional example ebuild"
HOMEPAGE="http://www.gentoo.org/"
SRC_URI="mirror://gentoo/${P}.tar.gz"

LICENSE="LGPL-2.1"
SLOT="0"
KEYWORDS="~amd64 ~ia64 ~ppc ~ppc64 ~sparc ~x86"
IUSE="java doc nls"

DEPEND="java? ( >=virtual/jdk-1.4 )"
RDEPEND="java? ( >=virtual/jre-1.4 )"

java_prepare() {
        epatch "${FILESDIR}/${P}.patch"
}

src_compile() {
        local myconf="$(use_enable java)"
        if use java; then
                myconf="${myconf} --with-javac-args=\"$(java-pkg_javac-args)\""
        fi

        econf $(use_enable nls) ${myconf} || die

        emake || die
}

src_install() {
        make install DESTDIR=${D} || die

        if use java; then
                java-pkg_newjar build/java/${P}.jar ${PN}.jar

                if use doc; then
                        java-pkg_dohtml -r doc/java
                fi
        fi
}

5.  Java Eclass Reference

Overview

Currently there are six Java related eclasses.

Eclass Usage
java-pkg-2.eclass Any and all java based packages
java-pkg-opt-2.eclass Package that have optional java support
java-ant-2.eclass Ant based packages (see also the Ant Guide)
java-utils-2.eclass Inherited by the java-pkg* eclasses and contains all the functions and dark voodoo
java-vm-2.eclass Helper functions for packages that provide a VM
java-osgi.eclass Helper functions for packages that need to be OSGi compliant (special manifest inside the jar)

java-pkg-2.eclass

This is the eclass you should for any package using Java. It inherits java-utils-2, and gives you all the needed function. It also depends on the correct version of java-config the eclass needs to do its work. It also exports the pkg_setup phase, where it switchs the vm and setup the environment for your VM.

java-pkg-opt-2.eclass

This is the eclass you should use for packages with optional java support. It does the same as java-pkg-2.eclass but only when the 'java' USE flag is on. The USE flag that is used to enable Java features can be changed by setting JAVA_PKG_OPT_USE before inheriting this eclass.

java-vm-2.eclass

This eclass should be inherited by all packages that provide a VM. If no system-vm can be found it will set the one currently being merged as the system-vm. It also has a function to install the env file and create all necessary symlinks.

java-ant-2.eclass

You should inherit this eclass when your package uses ant. This eclass automatically rewrites the build.xml unless JAVA_PKG_BSFIX is set to off. fex: Add source/target attributes to javac calls.

The rewriting is done in java-ant-2_src_configure for EAPI 2 or eant for earlier EAPIs.

Some variables you can set from your ebuild. (Usually not needed)

java-osgi.eclass

You should inherit this eclass when your package needs to be OSGi compliant. This eclass contains functions similar to those those in java-utils-2, but that create a jar containing a manifest with special values. This manifest will allow the jar to be used as an OSGi bundle in applications based on OSGi, for example Eclipse.

If a package is using this eclass, it means that another Gentoo package based on OSGi needs it. Thus, version bumps of the package should still use the install functions from this eclass.

Some of the functions in this eclass request a Manifest file. In this case, be careful about the file you provide. It's usually best to copy the Manifest from a safe source, eg. from Eclipse's bundled jars for example. Note that upstream Eclipse creates those files manually.

6.  java-utils-2.eclass

eant/ejavac

Since a lot of people prefer to compile their packages with jikes or eclipse-ecj, and it was becoming a hassle to add these in every ebuild we provide 2 wrapper scripts to call either ant with that compiler or that compiler itself.

It will read the file /etc/java-config/compilers.conf and try the entries front to end until it find an available(installed) compiler, and use it. It can contain any combination of: 'ecj' 'jikes' and 'javac'.

You should only use this if the package is known to work all 3 of the compilers, if later on a problem does occur with one of them, you can set JAVA_PKG_FILTER_COMPILER to it in the ebuild, and it will no longer try to use it.

It also listens to the JAVA_PKG_FORCE_COMPILER environment variable to force one of them, this can be useful when testing a new ebuild with every compiler.

Install functions

Query functions

Other functions

External variables

Some variables that can come in handy, you are not allowed to use these from an ebuild.

7.  External Resources