Since version 1.7.0, the way of packaging and using optional tasks in Apache Ant has changed substantionally. Previously, Ant was split into ant-core (the core .jar files) and ant-tasks (.jar files for all the optional tasks, most of which have quite a number of external package dependencies). Ant-tasks symlinked its jars into the ant-core/lib to be loaded. Dependencies of these optional tasks were hardcoded into the ant startup script and tried to be loaded even if they (or ant-tasks) were not installed. This way they would pollute the classpath for building and cause packages that also depend on some of these to build even without the dependencies recorded in ebuild and package.env.
With the new split-ant setup, each .jar file that made up ant-tasks package is installed as separate package (named ant-* as the jar file itself), specifying just the dep(s) it itself needs. The jars are not symlinked to ant-core/lib but instead, the presence of the package is recorded by touching a file named /usr/share/ant/tasks-${PV}/${PN}. Ant startup script is modified so that by default it looks into this directory and loads the tasks and their deps for backwards compatibility. But the real power lies in the ANT_TASKS variable (used in ebuild or by ant user) which can override this default behaviour and specify only the tasks you want it to load. To sum up, the advantages of new layout are:
To make the transition possible, dev-java/ant-core-1.7.0 needs to block on older versions of dev-java/ant-tasks and dev-java/ant. So when you encounter this block, just unmerge ant-tasks and ant, and reissue the emerge command that caused it. If you don't use Ant yourself, that's all you need to know.
If you use ant for your own Java development, you should be aware of few things. If you use only the tasks provided by Ant, there will not be any difference if you install the whole dev-java/ant meta-package. But the external libraries that used to symlink their .jar files into /usr/share/ant-core/lib to be loaded, will soon stop creating these symlinks. In order to load these libraries, you will now need to use the new ANT_TASKS environment variable, which takes space-separated list of packages to load.
Example of ant invocation with pmd and checkstyle libraries: ANT_TASKS="pmd checkstyle" ant
You can also use this variable to load libraries that didn't previously symlink into ant-core/lib, without the need to pass the full path with the -lib /path/to/jar parameter.
A developer writing ebuilds has to generally take care about two things - dependencies and ANT_TASKS variable. For dependencies, if you previously needed only dev-java/ant-core (which is added by java-ant-2 eclass automatically), nothing changes. But if your ebuild needed full dev-java/ant or dev-java/ant-tasks to compile, you should figure out which exact optional tasks are needed (more on that later) and specify them in DEPEND. Then, you need to list the tasks in ANT_TASKS variable before calling eant (can be different for each eant call). In the most simple case, the tasks you need don't depend on useflags, you don't care about specific versions and all eant() calls in your ebuild need the same set of tasks. Then you just list the tasks you need in WANT_ANT_TASKS variable *before* inheriting java-ant-2.eclass, and it will fill the DEPEND and ANT_TASKS for you. In the more complex cases, you have to specify all the depends yourself (maybe based on USE flags) and ANT_TASKS for each eant call (also maybe based on USE flags). Typically you do this with test flag and ant-junit.
Env variables to use and know how they work
Here are the order of how eant() processes these variables to export the final ANT_TASKS for calling the ant script, from highest lowest priority of overriding.
Usually you start with dev-java/ant-core as dependency ( added automatically with java-ant-2 eclass ) and see if you can compile the package. If it fails, see what class was missing and see the next section to determine what ant-* package you need to use. The failure looks like this:
Code Listing 3.1: Sample missing task error |
[junitreport] java.lang.ClassNotFoundException?: org.apache.tools.ant.taskdefs.optional.TraXLiaison |
Here you can see that the failing task was junitreport, and the class it was missing.
4. Implementation details (dev-java/ant* maintainer notes)
Build system (build.xml) changes
All ant-* ebuild share the same source tarball. Upstream's build.xml is already building different .jar files based on the classes dependencies, and there are selectors for the right source files. But it's using <available> statements to determine if dependency is present on classpath, and if not, it builds a manifest-only jar (or no jar at all, there's now a property for that in 1.7). We modify the build.xml to have separate target for core jars and target for the optional jars, where a property tells it which jar we want (easier to add 20 target differing just in name). We also make sure that only the source we want in the jar is compiled, and used for resolving internal class dependencies. Rest of these dependencies (for the optional jars) is resolved from symlinked ant.jar from the ant-core already installed on system, and in some cases also from ant-nodeps.jar (ant-nodeps package). This makes sure that all internal dependencies are represented with DEPEND variable in the ebuild and package.env.
Ant's launcher script now recognizes ANT_TASKS environment variable. The value is IFS-separated list of packages (in our usual package-slot format as recognized by java-config -p) that are translated to list of jar files (using java-config) and passed to ant with -lib parameter. There are also special values "none" and "all" (the default if not defined at all or empty). If "none" is specified, the only jars loaded by ant are those in /usr/share/ant-core/lib. This means no optional tasks, since they no longer symlink to here. Value of "all" will make the script load all tasks registered in /usr/share/ant/tasks(-version). The value of list can specify any ant-* tasks that are part of the ant distro itself, but also any external packages providing ant tasks (xjavac, ant-owanttasks) or in fact any package that provides something ant tasks can use (rhino for script tasks...).
We added one new eclass - ant-tasks.eclass used by the ant-* packages. Makes use of the shared build system, so ebuilds themselves only have to define few specific things. Is pretty well commented, so no details needed here. Few other java eclasses were modified to make use of the new features in other ebuilds. This is mostly about handling the ANT_TASKS variable and its friends WANT_ANT_TASKS and JAVA_PKG_FORCE_ANT_TASKS - see the developer docs. All changes and additions here are also commented.
The contents of this document are licensed under the Creative Commons - Attribution / Share Alike license.