I would like to add dependency to my Ant project; for example I want to add hibernate dependency to my project.
I'm new to Ant. Before I used maven tool to build project.
in maven it is very easy to add dependency to pom.xml file.
My build.xml file
<?xml version="1.0" encoding="UTF-8"?>
<project name="Demo ANT Project-1" default="run">
<target name="run" depends="compile">
<java classname="com.company.product.RoundTest">
<classpath path="staging"/>
</java>
</target>
<target name="compile">
<javac includeantruntime="false" srcdir="./src" destdir="staging" />
</target>
</project>
I want to add dependency to above Ant xml file.
PLEASE NOTE: This question was asked and answered newly 6 years ago.
First of all Ant is older than Maven and therefore does not include core support for dependency management.
Adding ivy
Ivy is a dependency management framework for Ant
http://ant.apache.org/ivy/
To enable it you need to do two things. First include the ivy task namespace to the top of your build file:
<project .... xmlns:ivy="antlib:org.apache.ivy.ant">
A secondly you'll need to install the ivy jar into one of the standard locations that ANT uses for it's 3rd party extensions:
$ANT_HOME/lib
$HOME/.ant/lib
I like to make my builds standalone so include a target that does this for me automatically:
<available classname="org.apache.ivy.Main" property="ivy.installed"/>
<target name="install-ivy" description="Install ivy" unless="ivy.installed">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.3.0/ivy-2.3.0.jar"/>
<fail message="Ivy has been installed. Run the build again"/>
</target>
Using ivy
This is a very extensive subject, the following is a simple example to download the hibernate jar and it's dependencies:
<target name="resolve" depends="install-ivy" description="Use ivy to resolve classpaths">
<ivy:cachepath pathid="compile.path">
<dependency org="org.hibernate" name="hibernate" rev="3.2.7.ga" conf="default">
<exclude org="javax.transaction"/>
</dependency>
</ivy:cachepath>
</target>
Produces the following output:
resolve:
[ivy:cachepath] :: Apache Ivy 2.3.0 - 20130110142753 :: http://ant.apache.org/ivy/ ::
[ivy:cachepath] :: loading settings :: url = jar:file:/home/mark/.ant/lib/ivy.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:cachepath] :: resolving dependencies :: #;working#mark
[ivy:cachepath] confs: [default]
[ivy:cachepath] found org.hibernate#hibernate;3.2.7.ga in public
[ivy:cachepath] found net.sf.ehcache#ehcache;1.2.3 in public
[ivy:cachepath] found commons-logging#commons-logging;1.0.4 in public
[ivy:cachepath] found asm#asm-attrs;1.5.3 in public
[ivy:cachepath] found dom4j#dom4j;1.6.1 in public
[ivy:cachepath] found antlr#antlr;2.7.6 in public
[ivy:cachepath] found cglib#cglib;2.1_3 in public
[ivy:cachepath] found asm#asm;1.5.3 in public
[ivy:cachepath] found commons-collections#commons-collections;2.1.1 in public
[ivy:cachepath] :: resolution report :: resolve 373ms :: artifacts dl 10ms
[ivy:cachepath] :: evicted modules:
[ivy:cachepath] commons-collections#commons-collections;2.1 by [commons-collections#commons-collections;2.1.1] in [default]
---------------------------------------------------------------------
| | modules || artifacts |
| conf | number| search|dwnlded|evicted|| number|dwnlded|
---------------------------------------------------------------------
| default | 10 | 0 | 0 | 1 || 9 | 0 |
---------------------------------------------------------------------
This ivy managed classpath can then be used in your javac task
<javac includeantruntime="false" srcdir="./src" destdir="staging" classpathref="compile.path"/>
Or simply put everything in one ant target ?
<target name="update-lib-dir">
<property name="ivy.install.version" value="2.4.0"/>
<property name="ivy.jar.file" value="lib-ant/ivy-${ivy.install.version}.jar"/>
<property name="lib-ivy.dir" value="lib-ivy"/>
<get src="https://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
dest="${ivy.jar.file}" usetimestamp="true" />
<taskdef resource="org/apache/ivy/ant/antlib.xml">
<classpath>
<pathelement location="${ivy.jar.file}"/>
</classpath>
</taskdef>
<!-- define your destination directory here -->
<retrieve pattern="${lib-ivy.dir}/[type]/[artifact]-[revision].[ext]" sync="true">
<!-- Add all your maven dependencies here -->
<dependency org="com.twelvemonkeys.imageio" name="imageio-jpeg" rev="3.4.2"/>
<dependency org="com.twelvemonkeys.imageio" name="imageio-tiff" rev="3.4.2"/>
</retrieve>
</target>
Note : Create your ivy library directory before. In this example, you should have at least a directory named lib-ant.
Hope it helps :o)
Related
I want to use an Ant task that is defined in an artifact. The artifact exists in the main Maven repositories and has some dependencies.
I want to use Ivy and Ant to:
Declare the dependency on that artifact and its transitive dependencies, so that they are resolved when the script is run.
Retrieve all the jar files as an Ant path, that I can feed into Ant's taskdef.
Refer to that set of resolved jar files in some other part of the build script.
So far, the documentation I have found does not optimize for this use case. Instead, it suggests to write the files ivy.xml, ivysettings.xml; I don't like that, the dependencies are small enough that I would like to fit everything in a single build script.
Any ideas?
The ivy cachepath task is a resolve task that can be used to create an ANT path. What is perhaps not well known is that this resolving task can also be used inline, in other words, you can specify the dependencies directly without an ivy file.
<ivy:cachepath pathid="tasks.path">
<dependency org="org.codehaus.groovy" name="groovy-all" rev="2.4.7" conf="default"/>
</ivy:cachepath>
For a related answer that utilizes an ivy file to manage multiple classpaths:
ivy:retrieve select which ivy.xml file to use
Example
The following example is a little contrived by demonstrates ivy downloading the jar associated with the groovy task. I have also included a utility target that I use to install the ivy jar as well.
build.xml
<project name="demo" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">
<available classname="org.apache.ivy.Main" property="ivy.installed"/>
<!--
============
Main targets
============
-->
<target name="resolve" depends="install-ivy">
<ivy:cachepath pathid="tasks.path">
<dependency org="org.codehaus.groovy" name="groovy-all" rev="2.4.7" conf="default"/>
</ivy:cachepath>
</target>
<target name="build" depends="resolve">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="tasks.path"/>
<groovy>
ant.echo "Hello world"
</groovy>
</target>
<!--
==================
Supporting targets
==================
-->
<target name="install-ivy" description="Install ivy" unless="ivy.installed">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.4.0/ivy-2.4.0.jar"/>
<fail message="Ivy has been installed. Run the build again"/>
</target>
<target name="clean" description="Cleanup build files">
<delete dir="${build.dir}"/>
</target>
<target name="clean-all" depends="clean" description="Additionally purge ivy cache">
<ivy:cleancache/>
</target>
</project>
I want to make project with two modules. App and server. Server depends on app. When I compile server I want to include class files from app into the build. But it resolves classpath relatively to server and not to app because of import issues. How to make ant resolve app locations relatively to app and server locations relatively to server. I din't get how it's done in ant docs. Could you please explain in a more simple way? Code snippet to clarify question little bit.
App build.xml:
<project name="app">
<property name="app.build.dir" location="build"/>
<target name="compile">
<echo message="Compiling app to ${app.build.dir}"/>
</target>
</project>
Server build.xml:
<project name="server">
<property name="server.build.dir" location="build"/>
<include file="../app/build.xml"/>
<target name="compile" depends="app.compile">
<echo message="Compiling server to ${server.build.dir} using classpath: ${app.build.dir}"/>
</target>
</project>
Output:
Buildfile: D:\work\test\ant-test2\server\build.xml
app.compile:
[echo] Compiling to D:\work\test\ant-test2\server\build
compile:
[echo] Compiling server to D:\work\test\ant-test2\server\build using classpath: D:\work\test\ant-test2\server\build
BUILD SUCCESSFUL
Total time: 0 seconds
Desired output:
Buildfile: D:\work\test\ant-test2\server\build.xml
app.compile:
[echo] Compiling to D:\work\test\ant-test2\app\build
compile:
[echo] Compiling server to D:\work\test\ant-test2\server\build using classpath: D:\work\test\ant-test2\app\build
BUILD SUCCESSFUL
Total time: 0 seconds
Multi module builds are difficult because there are no standards, each build author have his own approach to solving this problem.
My personal preference is to emulate how Maven does it. Each module creates and publishes a jar file to the "local" repository. This jar file is then a dependency of the other modules that consume its classes. This approach creates clean separation between modules and means you don't need to build the entire project when working on one sub-module.
So how is this done using ANT? Well you'll need to embrace another Maven concept, dependency management. The ivy plugin provides this feature to ANT.
Example
My dummy project. A single module called "app" which is dependency of the "server" module
├── build.xml <-- Builds all modules in correct order
├── app
│ ├── build.xml
│ ├── ivy.xml <-- Describes module dependencies
│ └── src
| ..
└── server
├── build.xml
├── ivy.xml <-- Dependency on the "app" module
└── src
..
Unless you customize locations, ivy uses the following directories to store files:
~/.ivy2/cache <-- Downloaded 3rd party dependencies go here
~/.ivy2/local <-- Repository which is private to the user.
Creating alternative storage locations and leveraging Maven repository managers is beyond the scope of this question.
After running this example by build produces the following explicitly versioned files:
~/.ivy2/local/com.myspotontheweb/demo-app/1.0.0/jars/demo-app.jar
~/.ivy2/local/com.myspotontheweb/demo-server/1.0.0/wars/demo-server.war
build.xml
Builds all modules in the correct order. This is determined by the module dependencies documented in each module's ivy.xml file (See ivy buildlist task). This is a very useful feature when you have a large number of interdependent modules.
<project name="demo" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">
<available classname="org.apache.ivy.Main" property="ivy.installed"/>
<target name="install-ivy" unless="ivy.installed">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.3.0/ivy-2.3.0.jar"/>
<fail message="Ivy has been installed. Run the build again"/>
</target>
<target name="build-list" depends="install-ivy">
<ivy:buildlist reference="build-path">
<fileset dir="." includes="**/build.xml" excludes="build.xml"/>
</ivy:buildlist>
</target>
<target name="build" depends="build-list">
<subant buildpathref="build-path">
<target name="clean"/>
<target name="publish"/>
</subant>
</target>
<target name="clean" depends="build-list">
<subant buildpathref="build-path">
<target name="clean"/>
</subant>
</target>
<target name="clean-all" depends="clean">
<ivy:cleancache/>
</target>
</project>
Notes:
Contains logic to ensure the ivy jar dependency is installed if missing
Ivy will cache downloaded 3rd party dependencies. The "clean-all" task is useful for ensuring the build is sweaky clean :-)
app/ivy.xml
Lists the 3rd party dependencies that the module has. This is a very useful Maven feature. Dependencies get downloaded automatically from Maven Central. No need to commit them into your source code repository.
<ivy-module version="2.0">
<info organisation="com.myspotontheweb" module="demo-app"/>
<configurations>
<conf name="compile" description="Required to compile application"/>
<conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
<conf name="test" description="Required for test only" extends="runtime"/>
</configurations>
<publications>
<artifact name="demo-app"/>
</publications>
<dependencies>
<!-- compile dependencies -->
<dependency org="org.slf4j" name="slf4j-api" rev="1.7.5" conf="compile->default"/>
<!-- runtime dependencies -->
<dependency org="org.slf4j" name="slf4j-log4j12" rev="1.7.5" conf="runtime->default"/>
<!-- test dependencies -->
<dependency org="junit" name="junit" rev="4.11" conf="test->default"/>
</dependencies>
</ivy-module>
Note:
Ivy configurations are used to classify and group dependencies. Used later to populate classpaths
app/build.xml
Pretty standard build process. Code is compiled tested and packaged. Note how ivy configurations are used to control the classpaths.
The "publish" target is worthy of special note it pushes the built jar into a local location where it can be picked up by other module builds.
<project name="demo-app" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">
<!--
================
Build properties
================
-->
<property name="src.dir" location="src/main/java"/>
<property name="resources.dir" location="src/main/resources"/>
<property name="test.src.dir" location="src/test/java"/>
<property name="build.dir" location="target"/>
<property name="dist.dir" location="${build.dir}/dist"/>
<property name="jar.main.class" value="org.demo.App"/>
<property name="jar.file" value="${dist.dir}/${ant.project.name}.jar"/>
<property name="pub.revision" value="1.0"/>
<property name="pub.resolver" value="local"/>
<!--
===========
Build setup
===========
-->
<target name="resolve" description="Use ivy to resolve classpaths">
<ivy:resolve/>
<ivy:report todir='${build.dir}/ivy-reports' graph='false' xml='false'/>
<ivy:cachepath pathid="compile.path" conf="compile"/>
<ivy:cachepath pathid="test.path" conf="test"/>
</target>
<!--
===============
Compile targets
===============
-->
<target name="resources" description="Copy resources into classpath">
<copy todir="${build.dir}/classes">
<fileset dir="${resources.dir}"/>
</copy>
</target>
<target name="compile" depends="resolve,resources" description="Compile code">
<mkdir dir="${build.dir}/classes"/>
<javac srcdir="${src.dir}" destdir="${build.dir}/classes" includeantruntime="false" debug="true" classpathref="compile.path"/>
</target>
<target name="compile-tests" depends="compile" description="Compile tests">
<mkdir dir="${build.dir}/test-classes"/>
<javac srcdir="${test.src.dir}" destdir="${build.dir}/test-classes" includeantruntime="false" debug="true">
<classpath>
<path refid="test.path"/>
<pathelement path="${build.dir}/classes"/>
</classpath>
</javac>
</target>
<!--
============
Test targets
============
-->
<target name="test" depends="compile-tests" description="Run unit tests">
<mkdir dir="${build.dir}/test-reports"/>
<junit printsummary="yes" haltonfailure="yes">
<classpath>
<path refid="test.path"/>
<pathelement path="${build.dir}/classes"/>
<pathelement path="${build.dir}/test-classes"/>
</classpath>
<formatter type="xml"/>
<batchtest fork="yes" todir="${build.dir}/test-reports">
<fileset dir="${test.src.dir}">
<include name="**/*Test*.java"/>
<exclude name="**/AllTests.java"/>
</fileset>
</batchtest>
</junit>
</target>
<!--
=====================
Build project
=====================
-->
<target name="build" depends="test" description="Create executable jar archive">
<ivy:retrieve pattern="${dist.dir}/lib/[artifact]-[revision](-[classifier]).[ext]" conf="runtime"/>
<manifestclasspath property="jar.classpath" jarfile="${jar.file}">
<classpath>
<fileset dir="${dist.dir}/lib" includes="*.jar"/>
</classpath>
</manifestclasspath>
<jar destfile="${jar.file}" basedir="${build.dir}/classes">
<manifest>
<attribute name="Main-Class" value="${jar.main.class}" />
<attribute name="Class-Path" value="${jar.classpath}" />
</manifest>
</jar>
</target>
<!--
=====================
Publish project
=====================
-->
<target name="publish" depends="build" description="Publish artifacts to shared repo">
<ivy:buildnumber organisation="${ivy.organisation}" module="${ivy.module}" revision="${pub.revision}"/>
<ivy:publish resolver="${pub.resolver}" pubrevision="${ivy.new.revision}">
<artifacts pattern="${build.dir}/dist/[artifact].[ext]"/>
</ivy:publish>
</target>
<!--
=============
Clean project
=============
-->
<target name="clean" description="Cleanup build files">
<delete dir="${build.dir}"/>
</target>
</project>
Notes:
The ivy buildnumber task is really useful for ensuring your build number is properly incremented each time you run a build. It looks at the files previously published.
server/ivy.xml
This module has a single dependency on the latest version of the "app" module. The actual revision number is determined at build time based on the files present in the local repository.
<ivy-module version="2.0">
<info organisation="com.myspotontheweb" module="demo-server"/>
<configurations>
<conf name="compile" description="Required to compile application"/>
<conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
<conf name="test" description="Required for test only" extends="runtime"/>
</configurations>
<publications>
<artifact name="demo-server" type="war"/>
</publications>
<dependencies>
<!-- runtime dependencies -->
<dependency org="com.myspotontheweb" name="demo-app" rev="latest.integration" conf="runtime"/>
</dependencies>
</ivy-module>
server/build.xml
This build just packages up the libraries into a WAR file. What makes it noteworthy is it's use of the ivy retrieve task. It will pull the "app" module dependency and all its transitive dependencies. It can be difficult to keep track of these manually.
<project name="demo-server" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">
<!--
================
Build properties
================
-->
<property name="build.dir" location="target"/>
<property name="dist.dir" location="${build.dir}/dist"/>
<property name="war.file" value="${dist.dir}/${ant.project.name}.war"/>
<property name="pub.revision" value="1.0"/>
<property name="pub.resolver" value="local"/>
<!--
===========
Build setup
===========
-->
<target name="resolve" description="Use ivy to resolve classpaths">
<ivy:resolve/>
<ivy:report todir='${build.dir}/ivy-reports' graph='false' xml='false'/>
</target>
<!--
=====================
Build project
=====================
-->
<target name="build" depends="resolve" description="Create executable jar archive">
<ivy:retrieve pattern="${build.dir}/lib/[artifact]-[revision](-[classifier]).[ext]" conf="runtime"/>
<war destfile="${war.file}" webxml="src/resources/web.xml">
<lib dir="${build.dir}/lib"/>
</war>
</target>
<!--
=====================
Publish project
=====================
-->
<target name="publish" depends="build" description="Publish artifacts to shared repo">
<ivy:buildnumber organisation="${ivy.organisation}" module="${ivy.module}" revision="${pub.revision}"/>
<ivy:publish resolver="${pub.resolver}" pubrevision="${ivy.new.revision}">
<artifacts pattern="${build.dir}/dist/[artifact].[ext]"/>
</ivy:publish>
</target>
<!--
=============
Clean project
=============
-->
<target name="clean" description="Cleanup build files">
<delete dir="${build.dir}"/>
</target>
</project>
A simple approach would be the following: In the build.xml for app instead of
<property name="app.build.dir" location="build"/>
use
<property name="app.build.dir" location="../app/build"/>
If you specify a property by location (and with a relative path), ant resolves the path relative to your current project. With this notation, ant first goes up a directory level and then down to the app dir, which is right from both of your projects.
A better approach would be to put the settings used by both build scripts in a separate property file and include this file from both builds.
Problem in running ant showing error Could not load definitions from resource axis-tasks.properties. It could not be found :
Here is the snapshot of build.xml on which the problem occurs
<target name="axis" depends="prepare">
<taskdef resource="axis-tasks.properties"/>
<axis-wsdl2java url="${webconsole.base}/src/myservice.wsdl"
output="${axis.output}">
<mapping
namespace="urn:myservice"
package="com.company.service" />
<mapping
namespace="http://webserviceurl.com"
package="com.company.service" />
</axis-wsdl2java>
</target>
When running ant shows following errors :
/build.xml:76: Problem: failed to create task or type axis-wsdl2java
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any <presetdef>/<macrodef> declarations have taken place.
Environment properties :
export TMPDIR=$HOME/tmp
export RELEASE=$HOME/Release
export JAVA_HOME=/usr/java/current
export ANT_HOME=/usr/local/apache-ant-1.6.5
export PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$PATH
Additional information
Actually, we have two build machines. First one has only root user and we have created /home/user folders manually e.g. /home/rajan etc. In this machine when we run ant as root from /home/rajan/R7_SP1_UTF8/vermaraj_R7_SP1/vobs/project/ip_src/AdminWebConsole ant works properly.
echo $PATH = /usr/java/current/bin:/usr/local/apache-ant-1.6.5/bin:/usr/lib/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
On the second machine, we have created individual user accounts and when we try and run ant either as root or rajan from /home/rajan/R7_SP1_UTF8/vermaraj_R7_SP1/vobs/project/ip_src/AdminWebConsole ant does not works properly.
echo $PATH : /usr/lib/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
Also, in both the build machines echo $CLASSPATH is empty
locate axis-ant.jar gives output as :
/home/Rajan/R7_SP1_UTF8/vermaraj_R7_SP1/vobs/project/ip_src/AdminWebConsole/lib/axis-ant.jar
/home/Rajan/R7_SP1_UTF8/vermaraj_R7_SP1/vobs/project/ip_src/AdminWebConsole/output/war/WEB-INF/lib/axis-ant.jar
/usr/local/apache-ant-1.6.5/lib/axis-ant.jar
ivy is not an option as this is part of very big code base, it may create problems if we add additional libraries.
The ANT task does appear to have a complex set of dependencies. I would recommend adding the ivy extension to manage these.
Example
├── build.xml
├── src
│ └── myservice.wsdl
└── target
└── output
└── com
└── examples
└── www
└── wsdl
└── HelloService_wsdl
├── Hello_BindingStub.java
├── Hello_PortType.java
├── Hello_Service.java
└── Hello_ServiceLocator.java
build.xml
<project name="demo" default="axis" xmlns:ivy="antlib:org.apache.ivy.ant">
<!--
================
Build properties
================
-->
<property name="build.dir" location="target"/>
<property name="axis.output" location="${build.dir}/output"/>
<available classname="org.apache.ivy.Main" property="ivy.installed"/>
<!--
===========
Targets
===========
-->
<target name="install-ivy" description="Install ivy" unless="ivy.installed">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.3.0/ivy-2.3.0.jar"/>
<fail message="Ivy has been installed. Run the build again"/>
</target>
<target name="resolve" depends="install-ivy" description="Use ivy to resolve classpaths">
<ivy:cachepath pathid="build.path">
<dependency org="org.apache.axis" name="axis-ant" rev="1.4" />
<dependency org="org.apache.axis" name="axis" rev="1.4" />
<dependency org="org.apache.axis" name="axis-jaxrpc" rev="1.4"/>
<dependency org="commons-logging" name="commons-logging" rev="1.1.1" />
<dependency org="commons-discovery" name="commons-discovery" rev="0.4" />
<dependency org="wsdl4j" name="wsdl4j" rev="1.6.2" />
</ivy:cachepath>
</target>
<target name="axis" depends="resolve" description="Run Axis task">
<taskdef resource="axis-tasks.properties" classpathref="build.path"/>
<mkdir dir="${axis.output}"/>
<axis-wsdl2java url="src/myservice.wsdl" output="${axis.output}">
<mapping namespace="urn:myservice" package="com.company.service" />
<mapping namespace="http://webserviceurl.com" package="com.company.service" />
</axis-wsdl2java>
</target>
<target name="clean" description="Clean workspace">
<delete dir="${build.dir}"/>
</target>
<target name="clean-all" depends="clean" description="Purge ivy cache">
<ivy:cleancache/>
</target>
</project>
axis-task.properties is part of axis-ant.jar, but it is not available for ant :
/build.xml:76: Problem: failed to create task or type axis-wsdl2java
it need's to be on ant classpath.
A simple way - but not recommended - is to put all axis jars in ANT_HOME/lib but that will pollute the ant core installation. Better put in it's own path as described here on axis.apache.org
Another way is to put all your ant addon libraries or third party jars in a special folder and make it available for ant via ANT_ARGS environment variable.
Either put this line in ANT_HOME/bin/ant.sh :
ANT_ARGS="-lib /usr/local/ant_xtralibs:/usr/local/ant_testlibs"
export ANT_ARGS
or create your own startscript as described here
Platform: Ubuntu 16.04 LTS
First of all, for that statement to be valid you need to use Axis 1 (download: here) and not Axis 2.
Then follow the instructions here to specify, among others, the classpath to be used.
Prior to that, the axis.home properties must be set manually in the build.xml from your binary installation root dir, i.e. /opt/local/axis-1_4/, or read from your environment variable AXIS_HOME,pointing to the same dir, like this:
<property environment="env"/>
<property name="axis.home" value="${env.AXIS_HOME}"/>
or set in the build.properties file.
Your *.jar subdir path could differ from ${axis.home}/build/lib, in my case it's ${axis.home}/lib.
I can't affect the procedure of copying classpath dependencies to WEB-INF/lib category: there is no special ANT task that copies those jars (at least, i cant find any 'copy' task with related "WEB-INF/lib" string as PATH argument), but they appeared after project building. How to affect this procedure? Basically, i need to exclude JAXB jars to avoid dependency conflict. At the same time i need this jars at compile-time, so i can't remove them. Maybe, it is easier to erase those jars manually, using 'delete' task?
What your struggling with is multiple classpath management. In a typical build there are at least 4 types of classpath:
compile: Classes that your code directly invokes
runtime: Classes that your code indirectly invokes via other classes
provided: Classes that you need to compile against, but whose implementation will be provided by the target platform
test: Additional classes (like junit) that are needed when you're testing code but which are not shipped with your final application
It was the Maven build tool which formally identified these common classpaths and provided a dependency management system for resolving and populating classpaths during the build process.
The bad news is that ANT pre-dates Maven and therefore leaves classpath management completely up to the programmer.... Typically this is done by putting jars into different directories or using complicated filesets within your build logic.
The good news is that there is an ANT plugin called ivy which performs Maven-like dependency management. It's worth learning, especially, if you program a lot with open source libraries (which increasingly use Maven now).
Example (without ivy)
The files which make up the individual classpaths must be managed at the top of the build. Obviously the files must be separately downloaded into the "lib" directory. As the number of files increases this approach becomes unwieldy.
<project name="demo" default="build">
<!--
================
File collections
================
-->
<fileset dir="lib" id="compile.files">
<include name="*.jar"/>
<exclude name="slf4j-log4j12.jar"/>
<exclude name="log4j.jar"/>
<exclude name="junit.jar"/>
<exclude name="hamcrest-core.jar"/>
</fileset>
<fileset dir="lib" id="runtime.files">
<include name="*.jar"/>
<exclude name="junit.jar"/>
<exclude name="hamcrest-core.jar"/>
</fileset>
<fileset dir="lib" id="test.files">
<include name="*.jar"/>
</fileset>
<!--
===============
Compile targets
===============
-->
..
..
<target name="compile" depends="init,resolve, resources" description="Compile code">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false" debug="true">
<classpath>
<fileset refid="compile.files"/>
</classpath>
</javac>
</target>
<!--
===============
Distribution targets
===============
-->
..
..
<target name="package" depends="test" description="Create the WAR file">
<copy todir="build/lib">
<fileset refid="runtime.files"/>
</copy>
<war destfile="${war.file}" webxml="${resources.dir}/web.xml">
<fileset dir="${resources.dir}" excludes="web.xml"/>
<lib dir="${build.dir}/lib"/>
</war>
</target>
Example (Using ivy)
Very high level introduction to ivy and it's tasks. See the "retrieve" ivy task below which delivers the functionality you're looking for.
build.xml
<project name="demo" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">
<!--
===========
Build setup
===========
-->
<target name="bootstrap" description="Install ivy">
<mkdir dir="${user.home}/.ant/lib"/>
<get src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.2.0/ivy-2.2.0.jar"
dest="${user.home}/.ant/lib/ivy.jar"/>
</target>
<!--
============================
Resolve project dependencies
============================
-->
<target name="resolve" description="Use ivy to resolve classpaths">
<ivy:resolve/>
<ivy:report todir='${ivy.reports.dir}' graph='false' xml='false'/>
<ivy:cachepath pathid="compile.path" conf="compile"/>
<ivy:cachepath pathid="runtime.path" conf="runtime"/>
<ivy:cachepath pathid="test.path" conf="test"/>
</target>
<!--
===============
Compile targets
===============
-->
..
..
<target name="compile" depends="init,resolve, resources" description="Compile code">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false" debug="true" classpathref="compile.path"/>
</target>
<!--
===============
Distribution targets
===============
-->
..
..
<target name="package" depends="test" description="Create the WAR file">
<ivy:retrieve pattern="${build.dir}/lib/[artifact].[ext]" conf="runtime"/>
<war destfile="${war.file}" webxml="${resources.dir}/web.xml">
<fileset dir="${resources.dir}" excludes="web.xml"/>
<lib dir="${build.dir}/lib"/>
</war>
</target>
Notes
The "bootstrap" target is designed to install ivy (It's not packaged with ANT core)
The "cachepath" task is used to create custom ANT paths
The "retrieve" task populates the WAR file's WEB-INF/lib directory with the jars needed at runtime (managed by ivy configuration)
ivy.xml
This file lists your project's dependencies. It uses configurations to logically group jars together and enables the ivy "cachpath" task to create matching classpaths within your build. Finally the 3rd party jars are downloaded and cached during the build process. This is very convenient and it means you can reduce the size of your project.
<ivy-module version="2.0">
<info organisation="com.myspotontheweb" module="demo"/>
<configurations>
<conf name="compile" description="Required to compile application"/>
<conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
<conf name="test" description="Required for test only" extends="runtime"/>
</configurations>
<dependencies>
<!-- compile dependencies -->
<dependency org="org.slf4j" name="slf4j-api" rev="1.7.2" conf="compile->default"/>
<!-- runtime dependencies -->
<dependency org="org.slf4j" name="slf4j-log4j12" rev="1.7.2" conf="runtime->default"/>
<!-- test dependencies -->
<dependency org="junit" name="junit" rev="4.10" conf="test->default"/>
</dependencies>
</ivy-module>
Hi i am trying to build an ant script that copies a certain lib file based on a if condition. however it doesnt seem to work as i get this error:
build.xml:20: fileset doesn't support the nested "if" element.
this is the part where it fails:
<target name="resolve">
<delete dir="${lib.dir}">
<include name="*" />
</delete>
<copy todir="${lib.dir}">
<fileset dir="ext-libs" >
<if name="${release}" value="true">
<include name="hello-client-[^DEBUG]*.jar" />
</if>
<else>
<include name="hello-client-*DEBUG.*.jar" />
</else>
</fileset>
</copy>
</target>
#JoseK is right. ANT filesets do not support nested "if" statements. In fact the "if" statement is not part of core ANT the recommended approach is to use conditional targets (See example)
#slipset is on the right track. Ivy configurations can be used to selectively choose your dependencies.
Example
This example is designed to be invoked in one of two ways
$ ant clean build
$ tree
.
|-- build.xml
|-- ivy.xml
`-- lib
|-- slf4j-api-1.6.4.jar
`-- slf4j-simple-1.6.4.jar
Or
$ ant -Drelease=1 clean build
$ tree
.
|-- build.xml
|-- ivy.xml
`-- lib
|-- logback-classic-1.0.3.jar
|-- logback-core-1.0.3.jar
`-- slf4j-api-1.6.4.jar
build.xml
<project name="demo" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="resolve">
<ivy:resolve/>
</target>
<target name="retrieve-alt" depends="resolve" unless="release">
<ivy:retrieve pattern="lib/[artifact]-[revision](-[classifier]).[ext]" conf="altruntime"/>
</target>
<target name="retrieve-release" depends="resolve" if="release">
<ivy:retrieve pattern="lib/[artifact]-[revision](-[classifier]).[ext]" conf="runtime"/>
</target>
<target name="build" depends="retrieve-alt,retrieve-release"/>
<target name="clean">
<delete dir="lib"/>
</target>
</project>
Notes:
The if and unless clauses on the targets perform a conditional test on the existence of the "release" property.
The ivy retrieve task uses a configuration to decide which jars should be used to populate the "lib" directory.
The retrieve pattern includes a "classifier" pattern, just in case you ivy mapping pulls down additional Maven artifacts like the source or javadoc jars.
ivy.xml
<ivy-module version="2.0">
<info organisation="com.myspotontheweb" module="demo"/>
<configurations>
<conf name="compile" description="Required to compile application"/>
<conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
<conf name="altruntime" description="Alternative 'runtime' configuration" extends="compile"/>
<conf name="test" description="Required for test only" extends="altruntime"/>
</configurations>
<dependencies>
<!-- compile dependencies -->
<dependency org="org.slf4j" name="slf4j-api" rev="1.6.4" conf="compile->default"/>
<!-- runtime dependencies -->
<dependency org="ch.qos.logback" name="logback-classic" rev="1.0.3" conf="runtime->default"/>
<!-- altruntime dependencies -->
<dependency org="org.slf4j" name="slf4j-simple" rev="1.6.4" conf="altruntime->default"/>
<!-- test dependencies -->
<dependency org="junit" name="junit" rev="4.10" conf="test->default"/>
</dependencies>
</ivy-module>
Note:
I would highly recommend always specifying a configuration mapping for each dependency. This will then map directly to how you intend to use the jars, for example populate a classpath.
Appendix
How to use ivy configurations
Ivy configurations can be used to emulate Maven scopes, but in fact an ivy configuration can represent any logical grouping of dependencies.
Here are the 3 standard classpaths required in any Java build:
<configurations>
<conf name="compile" description="Required to compile application"/>
<conf name="runtime" description="Additional run-time dependencies" extends="compile"/>
<conf name="test" description="Required for test only" extends="runtime"/>
</configurations>
Note the "extends" syntax that enables you to create larger sets. For example, the runtime set of jars also includes anything needed to compile the code your code.
Ivy configurations are difficult to understand until you realise that they can be used to selectively populate an ANT path:
<ivy:cachepath pathid="compile.path" conf="compile"/>
<javac ..... classpathref="compile.path"/>
Or used to selectively populate a directory
<ivy:retrieve pattern="build/WEB-INF/lib/[artifact].[ext]" conf="runtime"/>
Configuration mappings
Mappings are used to decide how groups of jars in your project relate to groups of jars in other projects.
This normally happens as follows:
<dependency org="org.slf4j" name="slf4j-api" rev="1.6.4" conf="compile->default"/>
Here our compile configuration is populate by the remote default configuration (normally the other modules compile dependencies)
Well, the apache docs are clear that you cannot nest an <if> within a <fileset>
You might have seen an example of the ant-contrib fileset task which does have the if as a conditional argument
You can download and use that instead.
I've done this a bit differently myself.
I've got
<target name="internal-resolve" description="retrieve dependencies with ivy">
<ivy:retrieve pattern = "${basedir}/lib/[conf]/[artifact].[ext]" conf = "${configuration}" />
</target>
Which puts the jars in a directory called lib/${configuration} where configuration is passed as a parameter in
<target name = "resolve-compile">
<antcall target = "internal-resolve">
<param name = "configuration" value = "compile"/>
</antcall>
</target>
So whenever resolve-compile is called, the jars are put in lib/compile.
This gives me:
<path id = "compile.class.path">
<fileset dir="${basedir}/lib/compile" includes="*.jar"/>
</path>
and finally
<target name="compile"
depends="init, resolve-compile"
description="Compile all Java-classes">
<javac deprecation="false"
encoding="utf8"
debug="true"
srcdir="${java.src.dir}"
destdir="${build.classes.dir}"
classpathref="compile.class.path"/>
</target>
Given this, you could easily created your own resolve-build which would drop your jars in lib/build
Granted, you'd then need to add a build configuration to your ivy.xml as
<configurations>
<conf name="compile" visibility="public" description="Whatever"/>
<conf name="build" visibility="public" description="Whatever"/>
</configuration>