Package Problem with Ant - java

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.

Related

bad name in value for --add-modules when trying to compile through ant

I am trying to include the javafx.controls module in my project and compile it through ant, rather then use javaFX javac --module-path "..\lib\javafx-sdk-17.0.2\lib" --add-modules javafx.controls App.java
java --module-path "..\lib\javafx-sdk-17.0.2\lib" --add-modules javafx.controls App commands to compile the file(s).
This is how my ant build.xml looks like right now:
<project name="projectName" default="dist">
<property file="build.properties"/>
<property file="${user.home}/build.properties"/>
<path id="run.classpath">
<fileset dir="${dist.dir}">
<include name="${project.name}.jar"/>
</fileset>
</path>
<target name="compile">
<mkdir dir="${build.dir}"/>
<javac srcdir="${src.dir}"
destdir="${build.dir}"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
includeantruntime="false">
<classpath>
<fileset dir="${lib.dir}/javafx-sdk-17.0.2/lib">
<include name="**/*.jar" />
</fileset>
</classpath>
<compilerarg line="--add-modules ${lib.dir}/javafx-sdk-17.0.2/lib/javafx.controls"/>
</javac>
</target>
<target name="dist" depends="compile">
<mkdir dir="${dist.dir}"/>
<jar jarfile="${dist.dir}/${project.name}.jar"
basedir="${build.dir}"
manifest="${src.dir}/Manifest.mf">
<zipgroupfileset dir="${lib.dir}/javafx-sdk-17.0.2/lib" includes="**/*.jar"/>
</jar>
</target>
<target name="build" depends="dist">
<java jar="${dist.dir}/${project.name}.jar" fork="true">
</java>
</target>
<target name="clean">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
</target>
</project>
The error I keep on getting is: error: bad name in value for --add-modules option: 'C:\xampp\htdocs\projectName/lib/javafx-sdk-17.0.2/lib/javafx.controls'. I have looked up the error, but the answers are very vague in my opinion and have not helped me get more knowledge in regards to the error.
What you are doing wrong
You are providing an incorrect value to --add-modules.
You are not providing a string to ant that matches the example command in your question.
In your question, for the example javac command, you have:
--module-path "..\lib\javafx-sdk-17.0.2\lib" --add-modules javafx.controls
but in your ant script you have
--add-modules ${lib.dir}/javafx-sdk-17.0.2/lib/javafx.controls
You have tried to compress the --module-path argument with the --add-modules argument. Those arguments must remain separate and have different values.
ant javac support for the Java Platform Module System
The ant javac task has a few parameters for working with the Java module system, you should use appropriate ones:
modulepath
Use this to reference the directory set containing your JavaFX modules (e.g. the SDK lib directory).
Do not put the JavaFX libraries on the class path, they are modules and belong on the module path.
Specific changes required for your ant script
I am not familiar enough with the ant argument syntax to provide the exact ant XML elements for the correct definitions of the arguments for your case.
If somebody knows the exact values required in ant element syntax, they can edit this answer and put the values here.
Background info
Read the javac man page if you want to understand what the --module-path and --add-modules arguments are, what data should be supplied to them, and the format required for that data.
Also review understanding java 9 modules.
Alternate approach: defining module info
As an alternative to adding modules via the --add-modules VM argument, you can instead define a module-info.java file in your application to make it modular and require the modules there.
This will work fine if you aren't depending on non-modular code.
Even if you define a module-info.java file, you still need to set the --module-path for the compiler and runtime so that it can find the module implementations. Build tools such as Maven will do this automatically for defined dependencies.
However, ant isn't aware of build dependencies and needs manual help with parameters to support the module system. You will need to set the module path manually via modulepath arguments to the compiler. Similarly, you will need to set VM arguments for runtime module support if you have a java execution task in ant.
solution
<target name="compile">
<mkdir dir="${build.dir}"/>
<javac srcdir="${src.dir}"
destdir="${build.dir}"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
optimize="${compile.optimize}"
includeantruntime="false">
<classpath>
<fileset dir="${lib.dir}/javafx-sdk-17.0.2/lib">
<include name="**/*.jar" />
</fileset>
</classpath>
<compilerarg line="--module-path ${lib.dir}/javafx-sdk-17.0.2/lib/"/>
<compilerarg line="--add-modules javafx.controls"/>
</javac>
</target>
<target name="build" depends="dist">
<java jar="${dist.dir}/${project.name}.jar" fork="true">
<jvmarg line="--module-path ${lib.dir}/javafx-sdk-17.0.2/lib/"/>
<jvmarg line="--add-modules javafx.controls"/>
</java>
</target>
First use the compilerarg with the line, to indicate what you want to compile during the javac process.
<compilerarg line="--module-path ${lib.dir}/javafx-sdk-17.0.2/lib/"/>
<compilerarg line="--add-modules javafx.controls"/>
You then provide these lines within the java process as well.
<jvmarg line="--module-path ${lib.dir}/javafx-sdk-17.0.2/lib/"/>
<jvmarg line="--add-modules javafx.controls"/>

equivalent of mvn build-classpath in ant

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.

ant cannot identify my jar files at all

I have my jar files in Assignment2\lib folder and my build file is in Assignment2. The name of the jar file is Assignment1.jar The following is how I tried to compile my Assignment2 from build file through ant.
<project name="Assignment1" default="run" basedir=".">
<property name="classes" value="classes" />
<path id="project.class.path">
<pathelement location="src"/>
<pathelement path="${java.class.path}/"/>
<pathelement path="${additional.path}"/>
</path>
<path id="lib.jars">
<fileset dir="lib" includes="**/*.jar" />
</path>
......
<target name="compile" description="compaling java files with Assignment2">
<mkdir dir="build"/>
<javac srcdir="src" destdir="build" debug="on" failonerror="true">
<classpath refid="project.class.path"/>
<classpath refid="lib.jars"/>
</javac>
</target>
<Project/>
I am getting compile errors. I'm using windows. Is that the problem? Is there any way to compile?
Well,Everything looks good to me but, you can try the following to validate the same,
Check if the lib folder has all the necessary library jars required to compile you application
You can try assigning the relative path of the lib folder to a property and refer it in the classpath eg: Property lib value=".\Lib"
Try the following before you call the compile target to see the list of jars being included in the classpath
<pathconvert property="libjars" refid="lib.jars"/>
<echo>libjars is ${classpathProp}</echo>
hey guys thanx for the answers actually i found probelm. i was trying to use a jar file created by netbeans files. Apparently netbeans jar files can be used only by netbeans. at the end i made a new jar file of Assingment1 and used it. now everything is fine. Thanx again for the answers.

Java: Ant script works like a charm, but Jar throws exceptions

I created my first Ant script and it's working pretty well. It compiles all my java sources, creates a .jar file and runs the program without even any warning.
But when i try to run my .jar from command line i get NoClassDefFoundError exceptions.
So, how to translate this Ant snippet to work from command line?
<property name="main.class" value="de.bfs.radon.omsimulation.OMMainFrame"/>
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
<target name="run" depends="jar">
<java fork="true" classname="${main.class}">
<classpath>
<path refid="classpath"/>
<path location="${bin.dir}/omsimulation-${version}.jar"/>
</classpath>
</java>
</target>
This is the command line:
# java -classpath lib/ -jar bin/omsimulation-0.4.45-beta3.jar
Throws:
Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: com/toedter/calendar/JDateChooser
at de.bfs.radon.omsimulation.OMMainFrame.(OMMainFrame.java:133)
at de.bfs.radon.omsimulation.OMMainFrame$1.run(OMMainFrame.java:106)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
Why does my .jar file not work with the defined classpath? Further down the Ant script:
<target name="jar" depends="manifest">
<mkdir dir="${bin.dir}" />
<jar jarfile="${bin.dir}/omsimulation-${version}.jar" manifest="${src.dir}/omsimulation.manifest" compress="no" basedir="${build.dir}" includes="de/**" />
</target>
<target name="manifest" depends="compile">
<manifestclasspath property="manifest.cp" jarfile="${bin.dir}/omsimulation-${version}.jar">
<classpath refid="classpath" />
</manifestclasspath>
<manifest file="${src.dir}/omsimulation.manifest">
<attribute name="Built-By" value="${author}"/>
<attribute name="Main-Class" value="${main.class}"/>
</manifest>
</target>
Again, running the Ant script works fine. I even tried adding the said libraries to my .jar but that only blows up the file size, the problem still persists.
<jar jarfile="${bin.dir}/omsimulation-${version}.jar" manifest="${src.dir}/omsimulation.manifest" compress="no" basedir="${build.dir}"> <!-- includes="de/**" /-->
<fileset dir="${lib.dir}">
<include name="**/*.jar" />
</fileset>
</jar>
Any ideas on this?
Thanks a lot,
donc_oe
SOLVED: Thanks to perception, the unix command line i was looking for is:
# java -cp lib/*:bin/myjarfile.jar my.package.MyMainClass
And for Windows (note the ; semicolon):
# javaw -cp lib/*;bin/myjarfile.jar my.package.MyMainClass
The relevant thing to note from your build script is this:
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
With that little snippet you have defined a path construct in Ant, which you then refer to in your run task:
<target name="run" depends="jar">
<java fork="true" classname="${main.class}">
<classpath>
<path refid="classpath"/>
<path location="${bin.dir}/omsimulation-${version}.jar"/>
</classpath>
</java>
</target>
This is in effect executing:
java -cp ${lib.dir}/*.jar:${bin.dir}/omsimulation-${version}.jar ${main.class}
Of course, it does so without the squigly lines and the path(s) fully substituted. The main point being that the command you are trying to run yourself is not equivalent at all. When attempting to invoke from the command line you will need to include in the classpath all the necessar JAR's containing your code and all third party libraries. Assuming everything is still bundled in the Ant created folders, something like:
java -cp <full-path-to-lib>/* -jar <full-path-to-bin>/omsimulation-0.4.45-beta3.jar
Or:
java -cp <full-path-to-lib?/*:<full-path-to-bin>/omsimulation-0.4.45-beta3.jar <MainClass>
ClassDefNotFoundException most likely occur when class is found in classpath, but it is loaded in different classloader, or in a wrong path etc.
From the build file, you appears to create jar that include other jars. This may not give a result you want.
Most likely you want a solution described in Easiest way to merge a release into one JAR file. My personal favorite is one-jar.

How to copy .java sources to Ant javac destFolder

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.

Categories