I know how to use Ant to copy files and folders but what I'm interested in is if, and how, I can have the javac task copy the same sources it's compiling to the output directory.
Basically, it's very similar to the option to include your sources in the jar task.
Why not simply use the copy task, along with the javac one ?
You can even use ant's macro to define your own copyingjavac task, that performs the two operations, with the only problem to correctly handle filesets, to copy exactly the set of files being compiled.
If you want to only copy a file when compilation succeeded, you will have to either build a custom ant task (extending the default javac task), or to play with ant_contrib foreach task.
The macrodef could look like:
<macrodef name="copyingjavac">
<attribute name="srcdir"/>
<attribute name="destdir""/>
<element name="arginclude"/>
<sequential>
<javac srcdir="#{srcdir}" destdir="#{destdir}" updatedProperty="build.success">
<arginclude/>
</javac>
<copy todir="#{destdir}">
<fileset dir="#{srcdir}">
<arginclude/>
</fileset>
</copy>
<fail unless="build.success">
Build failed. Check the output...
</fail>
</sequential>
</macrodef>
I found this answer on Ant's website (you can remove the "excludes" part to copy the .java sources along the compiled versions):
...
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
<copy todir="${classes.dir}">
<fileset dir="${src.dir}" excludes="**/*.java"/>
</copy>
</target>
...
This copies all resources (as long as they haven't the suffix ".java") to the build directory, so we could start the application from that directory and these files will included into the jar.
Related
I am beginner in Maven and Ant projects.I have a trouble with some Ant tasks.I don't know how to build class-path of dependencies in Ant; while it can be done in maven projects by:
mvn dependency:build-classpath
How can i do above task in Ant?
You can specify it using classpath tag in your build.xml you can refer example below
<target name="compile" depends="init" description="compile the source ">
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}/classes" includeantruntime="false">
<classpath>
<fileset dir="${hadoop.home}/">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${hadoop.home}">
<include name="hadoop-common-*.jar"/>
</fileset>
</classpath>
</javac>
</target>
Ant is more like an imperative programming language. You don't have the amount of meta-information in your build.xml as you have in a pom.xml. The easiest thing would be to add some code to your ant "compile" target that writes the classpath to a file when you do a compile.
You can also externalise the classpath in a separate libraries.xml file (that was done in our company when we used Ant) which allows you to edit and read the data more easily. You could even write another ant target for that.
I have a simple syntax for script files of a given extension that translates to java class files that I want to create, each containing a given function that can be invoked by reflection.
I want to write a main function that I can invoke from the ant script that can see the ant build directory, traverse it for all the files that have my extension, and translate each one to a java file that I put not in the bin directory but in the src directory package that holds the file (a script) with my extension.
Is this possible?
Andy
Here is an example of how you could create a .java file in the src directory for every .ext file in the bin directory.
But for code generation, I expect that you would need to implement a custom Ant task.
<project default="test">
<target name="test">
<copy todir="src">
<fileset dir="bin">
<include name="**/*.ext"/>
</fileset>
<globmapper from="*.ext" to="*.java"/>
<filterchain>
<!--
You will do some custom filtering
to create your new Java src file.
This is just for illustration.
-->
<headfilter lines="1"/>
<tokenfilter>
<replaceregex pattern=".*" replace="your new content"/>
</tokenfilter>
</filterchain>
</copy>
</target>
<!-- use with care! -->
<target name="clean">
<delete dir="src">
<include name="**/*.java"/>
</delete>
</target>
</project>
Try the ant-contrib project. It has a task which takes a fileset. You could then do whatever you want with it:
<ac:for param="file">
<fileset ... />
<sequential>
<echo message="#{file}" />
</sequential>
</ac:for>
Caveat: I'm the project owner of this. It does not yet take ant 1.7/1.8 constructs (ie. resource collections), but that effort is underway.
I want to include external jar to my java project. I'm using ant. External .jar is in folder lib. My build.xml looks something like that:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<path id="classpath">
<fileset dir="lib" includes="**/*.jar"/>
</path>
<target name="clean">
<delete dir="build"/>
</target>
<target name="compile">
<mkdir dir="build"/>
<javac srcdir="src" destdir="build" classpathref="classpath" />
</target>
<target name="jar">
<mkdir dir="trash"/>
<jar destfile="trash/test.jar" basedir="build">
<zipgroupfileset dir="lib" includes="**/*.jar"/>
<manifest>
<attribute name="Main-Class" value="com.Test"/>
</manifest>
</jar>
</target>
<target name="run">
<java jar="trash/test.jar" fork="true"/>
</target>
</project>
But it doesn't work. When I want to import something from the external .jar, there is an error after command ant compile: package com.something does not exist.. What should I edit to get it working?
Exact error:
Compiling 23 source files to xy/build
xy/src/com/Test.java:5: package com.thoughtworks.xstream does not exist
import com.thoughtworks.xstream.*;
^
1 error
You should try without the includes attribute:
<fileset dir="lib" />
And in the jar part you include the classes like this:
<zipgroupfileset includes="*.jar" dir="lib"/>
You can't put external libraries into a jar and expect the classloader to use those jars. Unfortunately this is not supported.
There are ant tasks like one jar that help you, to create a jar file, that contains everything you need.
This bit is from the background information of one jar:
Unfortunately this is does not work. The Java Launcher$AppClassLoader
does not know how to load classes from a Jar inside a Jar with this
kind of Class-Path. Trying to use
jar:file:jarname.jar!/commons-logging.jar also leads down a dead-end.
This approach will only work if you install (i.e. scatter) the
supporting Jar files into the directory where the jarname.jar file is
installed.
Another approach is to unpack all dependent Jar files and repack them
inside the jarname.jar file. This approach tends to be fragile and
slow, and can suffer from duplicate resource issues.
Other Alternative:
jarjar: Jar Jar Links is a utility that makes it easy to repackage Java libraries and embed them into your own distribution
I also use ant to include a number of dependency JARs in my JAR. My compile task looks like this. Perhaps something similar will work for you.
<target name="compile" depends="init">
<javac srcdir="${src}" destdir="${build}" includeantruntime="false">
<classpath>
<pathelement path="${classpath}" />
<fileset dir="${deps}">
<include name="**/*.jar"/>
</fileset>
</classpath>
</javac>
<copy todir="${build}">
<fileset dir="${src}" excludes="**/*.java"/>
</copy>
</target>
sometimes u can use jar contents directly, just unzip
<unzip src="/Developer-Java/mysql-connector-java/mysql-connector-java-5.1.22-bin.jar" dest="${build_dir}" />
I'm having a problem getting the javac used by Ant to find and use certain packages. When I invoke javac directly from the command line the packages are found and used.
The .jar files are located in my home directory under lib/java. This is my classpath:
/home/bliskovs/lib/java/*:/home/bliskovs/vendor/cytoscape-v2.7.0/cytoscape.jar
This is the relevant section in my build.xml:
<target name="compile">
<javac srcdir="." debug="true"/>
<javac srcdir="tools/" debug="true"/>
<javac srcdir="core/" debug="true"/>
</target>
How can I get Ant to recognize these packages?
Check out this.
<property name="build.classes.dir" location="build/classes"/>
<path id="compile.classpath">
<fileset dir="lib"/>
<pathelement location="/home/bliskovs/vendor/cytoscape-v2.7.0"/>
</path>
<target name="compile" description="Compile src dir">
<javac destdir="${build.classes.dir}" debug="true" includeantruntime="true">
<src location="src"/>
<classpath refid="compile.classpath"/>
</javac>
</target>
Define a classpath for the javac task. Relying on the CLASSPATH environment variable is a bad practice. It's even more true for the build process of a project, which should work without having to setup a whole lot of environment variables. If you start developing three or four projects at once, you'll understand why using a single CLASSPATH env variable is a bad idea.
See http://ant.apache.org/manual/Tasks/javac.html to know how to define a classpath inside the build.xml and use it in the javac task.
I have a target which has several copy tasks; It basically copies the common jars to our set of applications from a centralized location to the lib folder of the application.
Seeing as this is a regular copy task a jar will be copied only if it is newer than the one currently in the lib folder.
This is the relevant part in the build.xml:
<target name="libs"/>
<copy file=... />
<copy file=... />
<copy file=... />
<antcall target="clean_compiled_classes"/>
</target>
<target name="clean_compiled_classes" if="anyOfTheLibsWereCopied">
<delete .../>
</target>
I'm looking for a way to set the anyOfTheLibsWereCopied property before the ant call in the libs target based on whether or not any of the files has been actually changed.
Thanks,
Ittai
I would advise having a look at the Uptodate task. I have never used it before but I guess what you are trying to do will be implemented along the following lines:
<target name="libs"/>
<uptodate property="isUpToDate">
<srcfiles dir="${source.dir}" includes="**/*.jar"/>
<globmapper from="${source.dir}/*.jar" to="${destination.dir}/*.jar"/>
</uptodate>
<!-- tasks below will only be executed if
there were libs that needed an update -->
<antcall target="copy_libs"/>
<antcall target="clean_compiled_classes"/>
</target>
<target name="copy_libs" unless="isUpToDate">
<copy file=... />
<copy file=... />
<copy file=... />
</target>
<target name="clean_compiled_classes" unless="isUpToDate">
<delete .../>
</target>
Your other option would be to implement your own ant task that does what you want. This would require a bit more work though.