Ignoring system environment variables in ant - bash

I set this property in my build.xml script of ant to ignore the system classpath during build, but ant still picks up the system classpath in my java call and merges it with my classpath specified in the build script.
<property name="build.sysclasspath" value="ignore" />
<path id="classpath">
<pathelement path="${buildDir}/classes" />
<fileset dir="${prjdir}">
<include name="lib/*.jar"/>
</fileset>
</path>
<java classname="com.ibm.biginsights.fs.gpfs.LoggingInjector" failonerror="true">
<classpath refid="classpath" />
</java>
If I unset the $CLASSPATH environment variable before calling ant everything works fine. What's the problem?

ANT is itself a java program so it's difficult to prevent tasks from using the same system classpath.
To properly isolate your java build, I'd recommend to setting the following attributes on the javac task:
<javac .... includeAntRuntime="false" includeAntRuntime="false" ...
Similarily, when running java programs, set the fork attribute so that it runs in another VM:
<java ...fork="true" classpathref="class.path.that.i.control"...

This property, AFAIK, is a system property that must be passed to ant (using ant -Dbuild.sysclasspath=ignore). But unsetting the CLASSPATH is probably as easy.
The main problam, IMO, is to use the CLASSPATH environment variable in the first place. I find it preferrable to always use the -cp or -jar option whan using Java, and not to rely on the system CLASSPATH. As soon as you have two Java programs that both rely on the system CLASSPATH, there is a risk of a clash between the dependencies of these two programs.

Related

When causing a makefile to change directory and run ant in that new directory error "JAVA_HOME is not defined correctly"

Even if you have Java and/or ant installed through the windows installers, you still need to set your environment variables. Make sure you are linking your java to a JDK rather than a JRE, my guess as a newbie is that when you are compiling your own code you should always use the JDK as it has all the tools you need.
Original post:
This is all happening on Windows. I call make. It checks out a "code" folder from svn into the directory that makefile is in. Inside "code", is a build.xml. I want my makefile to change to that directory and then run ant on it. I am getting the error in my command prompt:
C:\Users\Ryan\Desktop\maketest>make
svn co (address removed)
Checked out revision 107.
cd code; ant clean compile jar run
uname: not found
basename: not found
dirname: not found
which: not found
Error: JAVA_HOME is not defined correctly.
We cannot execute java
make: *** [runant] Error 1
I checked here http://sunsite.ualberta.ca/Documentation/Gnu/make-3.79/html_chapter/make_5.html#SEC46 and it seems that this should be do-able in my makefile:
runant:
cd code; ant clean compile jar run
as this will open the command in a subshell but it will also run ant in that subshell.
This all works fine if I manually change into the code folder and run ant. I only get this JAVA_HOME not defined correctly error when I try to do this all from a single makefile.
makefile:
commands = checkoutcode checkoutdocs runant
svnCode = https://version-control.adelaide.edu.au/svn/SEPADL15S2UG7/code/
svnDocs = https://version-control.adelaide.edu.au/svn/SEPADL15S2UG7/updateDocs
ifdef version
REVISION = -r$(version)
endif
all: full
full: checkoutcode checkoutdocs runant
# ensure you use a single tab for the commands being run under that name
checkoutcode:
svn co $(svnCode) $(REVISION)
checkoutdocs:
svn co $(svnDocs) $(REVISION)
#change directory into the code folder and compile the code
runant:
cd code; ant clean compile jar run
build.xml:
<project>
<!-- add some property names to be referenced later. first one is lib folder to hold all libraries -->
<property name="lib.dir" value="lib"/>
<!-- images directory used to compile with the images and also add them to the jar -->
<property name="src/images.dir" value="images"/>
<!-- ensure the classpath can see all classes in the lib folder by adding **/*.jar -->
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
<!-- "Target" attribute is what we will write as a parameter to ant in the command prompt or terminal -->
<!-- eg. "ant clean" will run the commands inside the target tags, which is just to delete the directory
"build" -->
<target name="clean">
<delete dir="build"/>
<echo message="Cleaned "/>
</target>
<!-- compile command. creates a directory for the classes to be stored in, instead of the root folder
and then compiles everything in the src folder, using the classpath properties we set earlier -->
<target name="compile">
<mkdir dir="build/classes"/>
<javac includeantruntime="false" srcdir="src" destdir="build/classes" classpathref="classpath"/>
<echo message="Compiled "/>
</target>
<!-- jar command. this creates an executable jar file called Robot.jar which can run the program in full.
it uses the images and it uses the lejos libraries and embeds them into the jar -->
<target name="jar">
<jar destfile="Robot.jar" basedir="build/classes">
<fileset dir="src/images" />
<manifest>
<attribute name="Main-Class" value="Main"/>
</manifest>
<!-- this line adds everything in the lib folder to the classes being added to the jar,
ie. the lejos classes ev3 and pc -->
<zipgroupfileset dir="${lib.dir}" includes="**/*.jar" />
</jar>
<echo message="Created JAR "/>
</target>
<!-- run command. runs the program. Running the program in the command prompt or terminal is good
because it allows you to see any exceptions as they happen, rather than hiding them in eclipse -->
<target name="run">
<java jar="Robot.jar" fork="true"/>
<echo message="Run "/>
</target>
</project>
I am required to run this on different machines without any extra configuration performed, and will not be able to confirm the location of Java on those machines - the only guarantee I will get is that Java is installed and the environment variables work.
Just answering to allow you to mark as solved.
Even if you have installed Java with the oracle installer, you still need to create environements variables.
Even if you have Java and/or ant installed through the windows installers, you still need to set your environment variables. Make sure you are linking your java to a JDK rather than a JRE, my guess as a newbie is that when you are compiling your own code you should always use the JDK as it has all the tools you need.

javah cannot find dependent classes from spring-context-3.0.3.jar file

Am usning ANT tasks to compile java classes and then generate .h files using
javah [ version "1.7.0_55" ] on windows 7
following is the code snippet from my build.xml
...
<property name="build.dir" value="./main/test_target"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="external.lib.dir" value="./externalJars"/> <!-- contains spring-context-3.0.3.jar file -->
<property name="jni.output.dir" value="${build.dir}/jniHeaders"/>
..
...
<target name="compile-header" depends="build">
<exec executable="javah">
<arg line="-classpath ${classes.dir};${external.lib.dir} -o ${jni.output.dir}/MyNativeImpl.h -verbose -force examples.MyNativeImpl"/>
</exec>
</target>
...
..
But I am not able to generate the .h files and get the following ERROR
Error: Class org.springframework.context.MessageSource could not be found.
even though I have added "spring-context-3.0.3.jar" to externalJars dir => ${external.lib.dir}
My java file MyNativeImpl.java uses package "import org.springframework.context.MessageSource; "
Java file compilation goes fine using ${external.lib.dir} and MyNativeImpl.class also generated under ${classes.dir}
Not sure what am I doing wrong!!
Almost spend 1 day searching on SS but could find a specific solution.
I have many such dependent jars from spring framework to compile my app fully under ${external.lib.dir} hence wanted to know how could this be resolved so than JAVAH could find classes within .jar files !!
Surprisingly I have a work-around which is:
1. unzip the contents of pring-context-3.0.3.jar to CLASSES DIR ${classes.dir}
2. now my ${classes.dir} has following contents
a. examples/MyNativeImpl.class
b. org/springframework/context/MessageSource.class ( and other classes )
3. Now JAVAH doesn't complain and generate my MyNativeImpl.h
But I am now sure why it doesn't find the same MessageSource.class when I use spring-context-3.0.3.jar ??
Is there something I am missing or this is the only way :-( any help is highly appreciated.
Thanks in Advance
Regards,
Vivek
When specifying jars on a classpath, you must list each jar. The directory containing the jar is not enough, that only works for classes, explaining why your work-around works.
I suggest something like:
<path id="javah.path">
<pathelement location="${classes.dir}"/>
<fileset dir="${external.lib.dir}" includes="*.jar"/>
</path>
<pathconvert property="javah.classpath" refid="javah.path"/>
<exec executable="javah">
<arg line="-classpath ${javah.classpath} -o ... />
</exec>
PS
Why don't you use the javah ANT task?

ant conditional targets and 'recursion'

I'm fairly new to ant, and I've seen uncle Bob's "extract until you drop" episode.
As a result I try to define ant-targets as small as possibly possible, so you can see exactly the essence of the target, and no more. For more details, you have to refer to sub-targets.
Whether that's good or bad style is a different debate (or a flame-war maybe).
Therefore, I was creating a build script that, in pseudo-code, would look like this:
build =
compile
instrument if coverage
The coverage task is split into subtargets, too:
coverage:
create-coverage-dirs
call-cobertura
EDIT- I want to express that coverage sub-targets should not be run.
But... I'm having a hard time expressing this 'cleanly' in ant-ese.
Assuming that I can use the depends attribute to indicate ... inter-target dependencies, I got to something like this:
<target name="build" depends="compile, coverage"/>
<target name="compile"> .... </target>
<target name="coverage" depends="
create-coverage-dirs,
taskdef-cobertura"
if="build.with.coverage">
<cobertura-instrument ...> ... </cobertura-instrument>
</target>
<target name="create-coverage-dirs">
...
</target>
<target name="taskdef-cobertura">
...
</target>
Whow this looked nice!
Only it seemed that, when executing, the coverage task was duefully omitted, but it's sub-tasks were still executed when build.with.coverage was false!
>ant -v compile
Build sequence for target(s) `build' is
[compile, create-coverage-dirs, taskdef- cobertura, coverage, build]
Complete build sequence is
[compile, create-coverage-dirs, taskdef-cobertura, coverage, build, ]
I can put an if attribute in every coverage sub-task, but that doesn't seem clean to me.
So here's the question:
Is my ant-ese a horrible dialect? Am I 'making ant into make'?
Should if be used this way, or is there an if-and-recurse kind-of attribute?
Repeat after me: Ant is not a programming language. In fact, write it down 100 times on the blackboard.
Ant is not a programming language, so don't think of it as such. It is a build dependency matrix.
It's difficult for programmers to wrap their heads around that idea. They want to tell Ant each step and when it should be done. They want loops, if statements. They'll resort to having a build.sh script to call various targets in Ant because you can't easily program Ant.
In Ant, you specify discrete tasks, and which tasks depend upon other tasks, and let Ant handle where and when things get executed.
What I am saying is that you don't normally split tasks into sub-tasks and then try calling <ant> or <subant> on them.
Have discrete tasks, but then let each task know what other tasks they depend upon. Also remember that there is no true order in Ant. When you list the depends= tasks, there is no guarantee which order they'll be executed in.
Standard Ant Style (which means the way I do it (aka The Right Way), and not the way my colleague does it (aka The Wrong Way)), normally states to define tasks at the top of the properties file and not in any target. Here's a basic outline on how I structure my build.xml:
<project name=...>
<!-- Build Properties File -->
<property name="build.properties.file"
value="${basedir}/build.properties"/>
<property file="${build.properties.file"/>
<!-- Base Java Properties -->
<property name="..." value="..."/>
<taskdef/>
<taskdef/>
<!-- Javac properties -->
<property name="javac..." value="..."/>
<task/>
<task/>
</project>
This creates an interesting hierarchy. If you have a file called build.properties, it will override the properties as defined in the build.xml script. For example, you have:
<property name="copy.verbose" value="false"/>
<copy todir="${target}"
verbose="${copy.verbose}">
<fileset dir="${source}"/>
</copy>
You can turn on the verbose copy by merely setting copy.verbose = true in your build.properties file. And, you can specify a different build properties file by merely specifying this on the command line:
$ ant -Dbuild.properties.file="my.build.properties"
(Yes, yes, I know there's a -propertycommand line parameter for ant)
I normally set the various values in the build.xml to the assumed defaults, but anyone can change them by creating a build.properties file. And, since all the base properties are at the beginning, they're easy to find.
Tasks are defined in this non-target space too. That way, I can easily find the definition since they're in the same place in each build.xml, and I know I can use a task without worrying whether the task defining target has been hit.
Now, to your question:
Define your tasks (and don't have a tar defining task, or you'll drive yourself crazy). Then, define the dependencies on each of those tasks. Developers can select the targets they want to hit. For example:
<project>
<description>
yadda, yadda, yadda
</description>
<taskdef name="cobertura"/>
<target name="compile"
description="Compile the code"/>
<!-- Do you have to compile code before you run Cobertura?-->
<target name="coverage"
description="Calculate test coverage"
depends="compile">
<mkdir dir="${coverage.dir}"/>
<cobertura-instrument/>
</target>
<project>
If you want to compile your code, but not run any tests, you execute ant with the compile target. If you want to run tests, you execute ant with a coverage target. There's no need for the depends= parameter.
Also notice the description= parameter and the <description> task. That's because if you do this:
$ ant -p
Ant will show what's in the <description> task, all targets with a description parameter, and that description. This way, developers know what targets to use for what tasks.
By the way, I also recommend doing things the right way (aka doing it the way I do it) and name your targets after the Maven lifecycle goals. Why? Because it was a good way to standardize on the names of targets. Developers know that clean will remove all built artifacts, and compile will run the <javac> task, and that test will run the junit tests. Thus, you should use the goals in the Cobertura plugin: cobertura.
Edit
my problem is: I regard 'coverage' as related to 'optimized' and 'debug', i.e. a build flavor. That's where my difficulty lies: for Java, coverage results in an an extra intermediate target in the compile step.
I'm looking at the Corburta page, and there's no real change in the <javac> task (which is part of the compile target.
Instead, you run Corburtura on the already built .class files, and then run your <junit> task. The big change is in your <junit> task which must now include references to your Corburtura jars, and to your instrumented classes.
I imagine you could have a corburturatarget or what ever you want to call it. This target runs the instrumented JUnit tests. This is the target you want developers to hit, and should contain a description that it runs instrumented tests.
Of course, you can't run the instrumented Junit tests without first instrumenting them. Thus, your corburtura target will depend upon another instrument.tests target. This target is internal. People who run your build.xml don't normally say "instrument tests" without running those tests. Thus, this target has no description.
Of course, the instrument.tests target depends upon having .class files to instrument, so it will have a dependency upon the compile target that runs the <javac> task:
<target name="instrument.classes"
depends="compile">
<coburtura-instrument/>
</target>
<target name="corburtura"
depends="instrument.classes"
description="Runs the JUnit tests instrumented with Corburtura">
<junit/>
</target>
The only problem is that you're specifying your <junit> target twice: Once when instrumented, and once for normal testing. This might be a minor issue. If you update how your JUnit tests run, you have to do it in two places.
If you want to solve this issue, you can use <macrodef> to define a JUnit test running Macro. I used what was on the Corbertura page to help with the outline. Completely non-tested and probably full of syntax errors:
<target name="instrument.tests"
depends="compile">
<corburtura-instrument/>
</target>
<target name="corburtura"
depends="instrument.tests"
description="Instrument and run the JUnit tests">
<run.junit.test fork.flag="true">
<systemproperty.addition>
<sysproperty key="net.sourceforge.corbertura.datafile"
file="${basedir}/cobertura.ser" />
</systemproperty.addition>
<pre.classpath>
<classpath location="${instrumented.dir}" />
</pre.classpath>
<post.classpath>
<classpath refid="cobertura_classpath" />
</post.classpath>
</run.junit.test>
</target>
<target name="test"
description="Runs the Junit tests without any instrumentation">
<run.junit.test/>
</target>
<macrodef name="run.junit.test">
<attribute name="fork.flag" default="false"/>
<element name="sysproperty.addition" optional="yes"/>
<element name="pre.classpath" optional="yes"/>
<element name="post.classpath" optional="yes"/>
<sequential>
<junit fork="#{fork.flag}" dir="${basedir}" failureProperty="test.failed">
<systemproperty.addtion/>
<pre.classpath/>
<classpath location="${classes.dir}" />
<post.classpath/>
<formatter type="xml" />
<test name="${testcase}" todir="${reports.xml.dir}" if="testcase" />
<batchtest todir="${reports.xml.dir}" unless="testcase">
<fileset dir="${src.dir}">
<include name="**/*Test.java" />
</fileset>
</batchtest>
</junit>
</sequential>
</macrodef>
I would not use a property at all in this case, but rely solely on depends (which seems more natural to me for this task):
<target name="build" depends="compile, coverage"/>
<target name="compile"> ...
<target name="coverage"
depends="compile, instrument,
create-coverage-dirs, taskdef-cobertura"> ...
The if attribute tests if the property exists, not if it is true or false. If you don't want to run the coverage target then don't define the property build.with.coverage.
As of Ant 1.8.0 you can use property expansion to resplver property as a boolean:
<target name="coverage" depends="
create-coverage-dirs,
taskdef-cobertura"
if="${build.with.coverage}">

ant java task with space issue

I was trying to execute a jar file via ant script. Like this
<java jar="${jar.file}" fork="true" failonerror="true">
<arg line="${jar.args}"/>
</java>
jar.file has full path to the jar file and contains some space in it.
When I executed that on Linux, there was no problem. But when I do the same on Windows I got error. java task couldn't locate the jar! I've tried all different variations like wrapping the file path with quote ("), replaced space with ", tried escaping with backslash, etc. Non works!
Did anyone come across this issue? Just wondering if this is Ant's limitation or I missed something.
P.S Sorry for not providing the full error message I got. I'm away of my Windows PC right now. As a workaround, I decided to copy the jar to C:\ and used that instead.
The recommended way to handle space problems within properties is to put them in
extra '', which should work in most cases, even better to use a path without spaces
<java jar="'${jar.file}'" fork="true" failonerror="true">
<arg line="${jar.args}"/>
</java>
should work, as already mentioned in my comment.
edit
you're right it won't work because of the relative path with only jar attribute
in fact i thought of something like :
<project>
<property name="jar.file" value="foobar.jar"/>
<property name="jar.dir" value="/home/rosebud/temp/path with blanks"/>
<java
dir="${jar.dir}"
jar="${jar.dir}/${jar.file}"
fork="true"
failonerror="true"
>
<arg value="..." />
</java>
</project>
and it works unexpectedly also with spaces in path as f.e. in the snippet above
thought the standard way to handle space problems would fit in as in other cases :
"'${property with blanks}'"
but it doesn't.

How can I change a config file variable using ant build?

I'm using Jboss 4/5 and have some .war .properties files with default configuration settings
I want to update these settings using information from the windows xp environment variables.
${env} in ant
Import enviroment variables before including your property file:
build.xml file:
<target name="build">
<!-- load enviroment properties -->
<property environment="env" />
<property file="test.properties" />
<echo>test: ${test}</echo>
</target>
test.properties file:
test = ${env.TEMP}
I needed to up the build number in several files. Since I needed to keep the formatting of the file as well as the comments, I used replaceregexp. Be careful when writing your regular expressions that you limit the expression to only find the instances that you care about.
<replaceregexp
file="${dir.project}/build.properties"
match="(build\.number[ \t]*=).*"
replace="\1${build.number}"
flags="g"
/>

Resources