I must be not understanding the unless attribute properly. I have a properties file that has a property as follows:
module.project.enabled=false
module.finance.enabled=true
And in my Ant build file I have the following piece
<echo message="Finance module enabled is ${module.finance.enabled}"/>
<echo message="Project module enabled is ${module.project.enabled}"/>
<javac srcdir="src" destdir="${classes}" debug="true">
<classpath>
<pathelement path="src"/>
<fileset dir="web/WEB-INF/lib" includes="*.jar"/>
<fileset dir="lib" includes="*.jar"/>
<fileset dir="${GWT.HOME}" includes="gwt-user.jar,gwt-servlet.jar"/>
</classpath>
<exclude name="bla/finance/*.java" unless="${module.finance.enabled}"/>
<exclude name="bla/project/*.java" unless="${module.project.enabled}"/>
</javac>
When running my ant target the properties do seem to be read
[echo] Finance module enabled is true
[echo] Project module enabled is false
But when I look at the ${classes} directory I would have expected to see no classes in the project package and classes in the finance package but alas it seems to be excluding both packages?
For Ant 1.7 and prior, the if and unless attributes only check if a property is set. They don't actually check the value. You could in fact set it to anything, and that'll evaluate as true for if and false for unless. Likewise if you don't set it at all, you'll get false for if and true for unless.
In either case I'm not aware of the if and unless being available for <exclude>.
Related
I'm using the new Log4j2 - Java Logging Framework. If I specify the path to the configuration file in eclipse as VM argument -Dlog4j.configurationFile=/home/../config.xml everything works fine. The configure file is loaded and the logging works as expected, i.e. all logs are written to files. If I additionally use the -Dlog4j.debug, I get the corresponding debug messages from the framework which confirms the correct loading of my configuration file.
However, when I use ANT with a build.xml file the logging framework seems to be initialized with the default configuration - the logs no longer written to the files but to the console. I start the created prog.jar file with the following statement from the console:
java -Dlog4j.configurationFile=/home/../config.xml -Dlog4j.debug -jar prog.jar
The only debug message I get from to Log4j2 framework is the following:
DEBUG StatusLogger org.slf4j.helpers.Log4jLoggerFactory is not on classpath. Good!
In the following, parts of the build.xml file which I use to create prog.jar:
<target name="init">
<tstamp/>
<mkdir dir="${build}"/>
</target>
<path id="master-classpath">
<fileset dir="${lib}/apache-log4j-2.11.1-bin/">
<include name="log4j-api-2.11.1.jar"/>
<include name="log4j-core-2.11.1.jar"/>
</fileset>
</path>
<target name="compile" depends="init" description="compile the source">
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}" includeantruntime="true">
<classpath refid="master-classpath"/>
</javac>
</target>
<target name="jar" depends="compile" description="generate the distribution">
<mkdir dir="${dist}"/>
<jar jarfile="${dist}/prog.jar" basedir="${build}" compress="true">
<fileset dir="${src}" includes="**/*.java"/>
<zipgroupfileset dir="${lib}/apache-log4j-2.11.1-bin/" includes="*.jar" />
<manifest>
<attribute name="Main-Class" value="ch.zwas.aks.Runner"/>
</manifest>
</jar>
</target>
I'm confused why it works using Eclipse but does apparently not work when I create the project with ANT and specify the configuration file in the console. Furthermore, I have no idea why there are no more debug messages when I run the jar from the console.
Thanks for your support.
Thanks to the hint of Vikas Sachdeva I was able to solve the problem. The problem was that I apparently packed too many jar files from the log4j library into prog.jar. When I include just the following jar files it works as expected with ANT / console as well.
junit-X.jar
log4j-api-X.ja
log4j-core-X.jar
slf4j-api-X.jar
slf4j-simple-X.jar
The other jars which came with the log4j library I left out. It seems that Eclipse ignores these, but when included with the build.xml into to finally jar then they cause trouble.
So I'm extending my company's ant build script to add in a special module we want build in some cases. I've written an ant script that points to where I know the compiled class files for the rest of our codebase are, because they get compiled earlier in the build process. I know with 100% certainty the files are in this location.
However, whenever I try to compile this module, the classpath reference can't see those classes, and I get a bunch of "package does not exist" and "can't find symbol" errors.
I just can't seem to figure out what I'm doing wrong. Hoping for help here.
Here's my build script code:
<property name="classpath" value="${dir.dev}/out/production/Main"
<path id="pfClasspath">
<fileset dir="${classpath}">
<include name="**/*.class"/>
</fileset>
<fileset dir="${dir.dev.lib}">
<include name="**/*.jar" />
</fileset>
<fileset file="${lib.json}" /> <!-- TODO try removing this -->
</path>
<target name="compile" depends="prepare">
<javac source="1.7" classpathref="pfClasspath" srcdir="${dir.project}/src" destdir="${dir.project.build.classes}" />
</target>
The directory the "classpath" property is pointing at 100% contains all of the class files for the rest of the project. That level is the equivalent of the "src" directory on the sources side, immediately within it are the com/companyName/etc... folders.
My code contains references to the classes compiled at this location. Yet ant isn't finding them. Any help?
Try
<path id="pfClasspath">
<pathelement path="${classpath}" />
...
</path>
instead. Specifying the classpath does not mean to specify every single class file that's on the classpath, which is what you do when you define your <path> element using a <fileset>.
Below is the code for setting class path in ant.
<path id="build.classpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar" />
</fileset>
</path>
<target name="compile" depends="clean">
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="build.classpath" />
</target>
Why do we need to set classpath in ant ?
Think of ant as a framework to run your build tasks - compiling the code, running the (unit) tests, etc. In order to properly compile and execute your (test) code, java will need access to the third party libraries you may be using (e.g., JUnit for running unit tests). The classpath tells java where these JARs are located, so it can use them.
When I use a path reference ID, Ant seems to evaluate any variables inside the definition before any tasks run. For example, ${common.dist} and ${common.lib} below seem to be evaluated before any tasks run.
<path id="compile.classpath">
<fileset dir="lib">
<include name="*.jar" />
</fileset>
<fileset dir="${common.dist}">
<include name="*.jar" />
</fileset>
<fileset dir="${common.lib}">
<include name="*.jar" />
</fileset>
</path>
In the Ant output I see something like this:
Adding reference: compile.classpath
Property "common.dist" has not been set
Property "common.lib" has not been set
...
Build sequence for target(s) `package' is [...]
Complete build sequence is [...]
This makes it seem like the path reference is being processed before any targets are run.
I have a compile target like this:
<target name="compile" depends="init,common">
<javac destdir="build/classes" debug="true" deprecation="true" optimize="true">
<src path="src/java" />
<classpath>
<path refid="compile.classpath" />
</classpath>
</javac>
</target>
If I copy the guts of the path reference into the classpath element inside the compile target, things seem to work fine.
Any tasks outside a target are executed on every build, in order of appearance in the build.xml, before any targets are run. If you want to use properties in a <path> defined outside a target then you need to put the <property> task that defines the properties also outside a target, and before the <path>. If you need to load the properties within a target then you'll have to put the <path> definition inside a target too (either the same one or one that runs after the one defining the properties).
See this question (and my answer) for more details.
The answer is in the Ant manual - path like structures:
By default a path like structure will re-evaluate all nested resource
collections whenever it is used, which may lead to unnecessary
re-scanning of the filesystem ...
I think you maybe forgot to set the ${common.dist} and ${common.lib} properties. They should be outside any target:
<property name="common.dist" location="dist"/>
<property name="common.lib" location="lib"/>
How can I get the CLASSPATH from the environment in a build.xml?
I've tried
<property environment="env"/>
<path id="classpath">
<pathelement location="${env.CLASSPATH}"/>
</path>
<target name="compile">
<javac includeantruntime="false">
<src path="${src}"/>
<classpath refid="classpath"/>
</javac>
</target>
I have a feeling this is failing because ${env.CLASSPATH} is a colon-separated list.
How then, can I get my classpath? I was surprised when ant didn't use my environment's CLASSPATH.
EDIT:
I've found a quick solution, but the preferred method is to use a separate properties file like the example here http://www.java2s.com/Code/Java/Ant/Useseparatepropertyfile.htm
Solution is, add
<property name="build.sysclasspath" value="first"/>
to the top of the build.xml
Yes, it's failing because it's a colon-separated list. In general, it's considered a bad idea to specify the class-path externally and use it within Ant. This is because running the same Ant script on different machines may yield different results. Instead, you're better of specifying the class-path from within Ant.