Ant Guide
1.
Split-Ant
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:
-
-
Reduced dependencies of packages that need more than ant-core
(instead of depending in whole ant-tasks with its almost 20
direct dependencies, you specify only those you want)
-
Less classpath pollution, no hardcoded dependencies inside ant
startup script (see above)
-
Easy to find if you need more than ant-core to build a package
(with old setup you would have to unmerge ant-tasks to test if
package fails without them)
-
Allows us to have junit3 and junit4 in separate slots and
choose which one to load in ant
-
Better controlled build of the jars, instead of a
manifest-only jar it will fail if there's something wrong with
the dependency package
-
Full backward compatibility with existing ebuilds
2.
End User Documentation
Migrating to Ant 1.7.0
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.
Working with new setup
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.
3.
Ebuild Developer Guide
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
-
-
ANT_TASKS - $IFS-separated list of optional tasks (ant-foo) or
even external libraries ant can use (xjavac...) to load. Used
by eant. You can't set this in ebuild global scope, use only
inside src_compile() or src_test()
-
WANT_ANT_TASKS - like ANT_TASKS, but you specify this before
inheriting java-ant-2 and it can contain only ant-* tasks. Will
be translated into dev-java/ant-* in DEPEND and used as default
ANT_TASKS if you don't set (override) it yourself.
-
EANT_ANT_TASKS - if you use the default src_compile() of
java-pkg-2, and can't use WANT_ANT_TASKS for some reason,
set this in the global scope to pass ANT_TASKS value to it.
-
JAVA_PKG_FORCE_ANT_TASKS - like ANT_TASKS, but you don't use
this in ebuild, but in the env, overrides any ANT_TASKS and
WANT_ANT_TASKS set in the ebuild (in eant, does not bring the
deps, because of portage dep caching). Can be used to easily
hash out which tasks you need when writing the ebuild, without
need to alter it each time.
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.
-
-
JAVA_PKG_FORCE_ANT_TASKS (set in the environment)
-
ANT_TASKS (set in the src_* function calling eant())
-
EANT_ANT_TASKS (for java-pkg-2 default src_compile())
-
WANT_ANT_TASKS (set in the ebuild global scope before inherit)
-
"none" (the default)
Typical workflow
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.
Launcher script changes
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...).
Eclasses
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, unless otherwise expressly stated, are licensed under the CC-BY-SA-2.5 license. The Gentoo Name and Logo Usage Guidelines apply.
|