Specifying the Eclipse compiler completely from _within_ build.xml - java

As an experiment we want to build our products using the Eclipse java compiler (ecj-3.5.jar downloaded from eclipse.org) on the runtime version of Java 6 instead of the JDK, and as I understand it, it is a matter of adding this jar to the ant classpath, and setting the build.compiler property to point to the adapter.
By including
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />
in my build.xml and invoking ant with a JRE, I get the expected error that the adapter cannot be found, and by adding ecj-3.5.jar to the classpath in the Eclipse panel I can compile my code as expected. I believe the same functionality to be available with "-lib foo.jar" from the command line with modern ants.
Now, I want to specify from within build.xml that I want ecj-3.5.jar on my classpath satisfying the same as above. We can already do this with ant tasks, so I believe it is possible.
So the question is: How can I add to the classpath used by javac to locate the compiler only from within build.xml?
It appears that the upcoming ant4eclipse 1.0 includes the Eclipse compiler (which is what I wanted to use this for), so by upgrading to that (from 0.5) should solve the problem we have.
2010-09-24: Ant4Eclipse is still at M4 without indication of when the release will happen.
2011-12-01: We have now migrated from ant to maven. The build.xml scripts hit the complexity wall and a fresh approach was needed. Anyone needing to choose what to do - do not go the ant4eclipse path except for trivial projects.
2012-11-30: A year later, the maven experience is still mostly good. There is a lot of quirks and changes in mindset but most make sense in the context. Maven can specify the compiler level on individual projects easily. We are looking into using ecj instead of javac (for several reasons) but for most purposes javac works nicely.

One way is to specify a reference to a componentdef when using javac.
<componentdef name="ecj"
classname="org.eclipse.jdt.core.JDTCompilerAdapter"
classpath="ecj-3.7.1.jar" />
<javac ....>
<ecj/>
</javac>
Another option is to set build.compiler as you have or the compiler attribute for javac and then specify a compilerclasspath for javac. This is a normal path like structure to hold the classpath for loading your compiler adapter.
<javac compiler="org.eclipse.jdt.core.JDTCompilerAdapter" ....>
<compilerclasspath>
...
</compilerclasspath>
</javac>
See the javac task documentation in the Ant manual for more details. Note that both these both solutions only work from Ant 1.8 onwards.

Reading Running Ant via Java. I think you can write a simple wrapper that will properly set a classpath and add your jar file to the resulting class path.
Here I'm just cutting and pasting the sample from the above link with addition of the library that you are interested in to the classpath:
<java
classname="org.apache.tools.ant.launch.Launcher"
fork="true"
failonerror="true"
dir="${sub.builddir}"
timeout="4000000"
taskname="startAnt"
>
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
<pathelement location="/path/to/ecj-3.5.jar"/>
</classpath>
<arg value="-buildfile"/>
<arg file="${sub.buildfile}"/>
<arg value="-Dthis=this"/>
<arg value="-Dthat=that"/>
<arg value="-Dbasedir=${sub.builddir}"/>
<arg value="-Dthe.other=the.other"/>
<arg value="${sub.target}"/>
</java>
I think you can even reuse the same build file, just give a different target as an entry point.

Related

Skip DLL compilation if no changes

I'm attempting to optimize our build procedure for our applications we have here. I'd like to skip the compilation of our backend .dll file should the file timestamp not have change using Netbeans Ant scripts.
I've been using Incremental and fast build using Ant and Advanced Free-form project configuration as a reference point but it seems to require 2 build targets to create the .timestamp comparison in the first link.
Is there a way to circumvent the need for 2 targets and check the timestamp of the .dll file instead? or do I simply need to add another tag inside of my call to make the comparison, or is what I'm trying to do not feasible?
Any help would be greatly appreciated or if better methods of doing this are known I am open to listening to it.
We use Netbeans to compile our projects, and uses Ant by default. I've included a snippit of my build.xml Ant script so far.
Thanks in advance!
<target name="init-skip-dll" description="initializes the skip property for the Ada dll">
<uptodate srcfile="create-ada-dll.timestamp" targetfile="ada-dll.timestamp" property="ada-dll.skip" value="true" />
</target>
<target name="-build-dll" description="builds the Ada dll if needed" depends="init-skip-dll">
<exec executable="gprbuild.exe">
<arg value="-P"/>
<arg file="..\DLL\ifccs_dll.gpr"/>
</exec>
<touch file="create-ada-dll.timestamp"/>
</target>
I don’t use Ant, but the same problem exists with Make; the Ada dependency rules are complex, and best handled by unconditionally letting gprbuild do whatever it needs to to bring the DLL up-to-date. Gprbuild will do nothing besides checking dependencies if the DLL is actually up-to-date.
In Make, this involves a phony target: e.g. for a real target testbed,
testbed: force
gprbuild -p -P testbed
.PHONY: force
or for an already-phony target
all:
gprbuild -p -P build_runtime.gpr
.PHONY: all
By the way, note the -p, which says to create needed directories, e.g. an object directory.

Using changeset number in a java program

I am using Mercurial HG for versioning my projects. To keep my version-number in my build/compiled programs uptodate I am using this approach. I've modified the build.xml to override a predefined target.
<target name="-pre-compile">
<!-- getting the version in a fancy format -->
<exec executable="hg" outputproperty="version.mercurial">
<arg value="parent"/>
<arg value="--template"/>
<arg value="{latesttag}.{rev}-{branch}-{node|short}"/>
</exec>
<echo level="warning">Version ${version.mercurial}</echo>
<manifest file="${manifest.file}" mode="update">
<attribute name="Implementation-Version" value="${version.mercurial}"/>
</manifest>
</target>
** note hg.exe is in my classpath.
To retrieve the version property I use the following code snippet in my mainclass
String version = Main.class.getPackage().getImplementationVersion();
When I build my project and run it with this java -jar myproject.jar the version number is correct and from that point everything is fine.
But when I run it in my IDE the version string ist null, so the manifest file isn't read.
So this makes me thinking if this approach is valid or is there another, even a simpler way to keep the version number uptodate?
EDIT: Is there a more sophisticated way to include the version number into your program?
Consider using the output attribute to Ant's <exec ..> task to write a properties file instead. Then you can use the <properties file="..."> method to read it in Ant, and can load it like a normal properties file when running in your IDE.
Good for you for not using the KeywordsExtension for this. It's a horrible solution in a DVCS world.

Running GWT from Ant buildfile with special arguments?

I would like to run the GWT compiler from my Ant buildfile with the compiler the following flags:
-compileReport
-XsoycDetailed
-extra
-XfragmentCount <x> (where <x> is an integer that I'll determine over time)
I looked into ant-gwt, which seemed pretty stable, however after a thorough inspection of the documentation and code, it doesn't seem like that plugin can handle these GWT compiler options.
Checking out the GWT command-line tools, I see a code snippet for an Ant task that runs a GWT class called com.google.gwt.dev.Compiler from inside a buildfile:
<java failonerror="true" fork="true" classname="com.google.gwt.dev.Compiler">
<classpath>
<pathelement location="src"/>
<path refid="project.class.path"/>
</classpath>
<!-- add jvmarg -Xss16M or similar if you see a StackOverflowError -->
<jvmarg value="-Xmx256M"/>
<!-- Additional arguments like -style PRETTY or -logLevel DEBUG -->
<arg value="com.example.foo.Foo"/>
</java>
Is this the correct way to run the GWT compiler from Ant (that ant-gwt probably wraps)? I think the word dev in the package name is throwing me off: is this some smart compiler stub or is it actually the GWT compiler?
If not, then what is the proper way to run GWT from inside of Ant? The only other thing I can think of would be to kick off a Python script from inside the Ant task, and have the Python script call the GWT compiler, but even then, not sure what command-line tool to call from that Python script (maybe webAppCreator?). Thanks in advance.
After downloading GWT from http://code.google.com/p/google-web-toolkit/downloads/list, extract the content from zip folder. Please refer the build scripts "build.xml" provided by GWT team in "sample" folder projects like "Hello" .
or
Example Hello World Ant build.xml
Modify 4th line to add your compiler options - <property name="gwt.args" value="-draftCompile -ea -style pretty -logLevel TRACE -workDir work" />
com.google.gwt.dev.Compiler is the GWT compiler; dev is for developer tools: compiler, DevMode, etc.
BTW, the documentation for the compiler is here.

ant warning: "'includeantruntime' was not set"

I receive the following warning:
[javac] build.xml:9: warning: 'includeantruntime' was not set,
defaulting to build.sysclasspath=last; set to false for repeatable builds
What does this mean?
Ant Runtime
Simply set includeantruntime="false":
<javac includeantruntime="false" ...>...</javac>
If you have to use the javac-task multiple times you might want to consider using PreSetDef to define your own javac-task that always sets includeantruntime="false".
Additional Details
From http://www.coderanch.com/t/503097/tools/warning-includeantruntime-was-not-set:
That's caused by a misfeature
introduced in Ant 1.8. Just add an
attribute of that name to the javac
task, set it to false, and forget it
ever happened.
From http://ant.apache.org/manual/Tasks/javac.html:
Whether to include the Ant run-time
libraries in the classpath; defaults
to yes, unless build.sysclasspath is
set. It is usually best to set this to
false so the script's behavior is not
sensitive to the environment in which
it is run.
As #Daniel Kutik mentioned, presetdef is a good option. Especially if one is working on a project with many build.xml files which one cannot, or prefers not to, edit (e.g., those from third-parties.)
To use presetdef, add these lines in your top-level build.xml file:
<presetdef name="javac">
<javac includeantruntime="false" />
</presetdef>
Now all subsequent javac tasks will essentially inherit includeantruntime="false". If your projects do actually need ant runtime libraries, you can either add them explicitly to your build files OR set includeantruntime="true". The latter will also get rid of warnings.
Subsequent javac tasks can still explicitly change this if desired, for example:
<javac destdir="out" includeantruntime="true">
<src path="foo.java" />
<src path="bar.java" />
</javac>
I'd recommend against using ANT_OPTS. It works, but it defeats the purpose of the warning. The warning tells one that one's build might behave differently on another system. Using ANT_OPTS makes this even more likely because now every system needs to use ANT_OPTS in the same way. Also, ANT_OPTS will apply globally, suppressing warnings willy-nilly in all your projects
Chet Hosey wrote a nice explanation here:
Historically, Ant always included its own runtime in the classpath made available to the javac task. So any libraries included with Ant, and any libraries available to ant, are automatically in your build's classpath whether you like it or not.
It was decided that this probably wasn't what most people wanted. So now there's an option for it.
If you choose "true" (for includeantruntime), then at least you know that your build classpath will include the Ant runtime. If you choose "false" then you are accepting the fact that the build behavior will change between older versions and 1.8+.
As annoyed as you are to see this warning, you'd be even less happy if your builds broke entirely. Keeping this default behavior allows unmodified build files to work consistently between versions of Ant.
The answer from Daniel works just perfect. Here is a sample snippet that I added to my build.xml:
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false">
<!-- ^^^^^^^^^^^^^^^^^^^^^^^^^ -->
<classpath>
<path id="application" location="${jar.dir}/${ant.project.name}.jar"/>
<path id="junit" location="${lib.dir}/junit-4.9b2.jar"/>
</classpath>
</javac>
</target>
If you like me work from commandline the quick answer is executing
export ANT_OPTS=-Dbuild.sysclasspath=ignore
And then run your ant script again.
Use <property name="build.sysclasspath" value="last"/> in your build.xml file
For more details search includeAntRuntime in Ant javac
Other possible values could be found here
i faced this same, i check in in program and feature. there was an update has install for jdk1.8 which is not compatible with my old setting(jdk1.6.0) for ant in eclipse.
I install that update.
right now, my ant project is build success.
Try it, hope this will be helpful.

How to emulate "-lib foo.jar" from _within_ build.xml

By specifying "-lib foo.jar" to ant I get the behaviour that the classes in foo.jar is added to the ant classloader and are available for various tasks taking a class name argument.
I'd like to be able to specify the same behaviour but only from inside build.xml (so we can do this on a vanilla ant).
For taskdefs we have functioning code looking like:
<taskdef resource="net/sf/antcontrib/antlib.xml" description="for/foreach tasks">
<classpath>
<pathelement location="${active.workspace}/ant-contrib-1.X/lib/ant-contrib.jar" />
</classpath>
</taskdef>
where the definition is completely provided from the ant-contrib.jar listed.
What is the equivalent mechanism for the "global" ant classpath?
(I have thought out that this is the way to get <javac> use ecj-3.5.jar to compile with on a JRE - Specifying the Eclipse compiler completely from _within_ build.xml - in a way compatible with ant 1.7. Better suggestions are welcome :)
EDIT: It appears that the about-to-be-released version 1.0 of ant4eclipse includes ecj. This does not answer the question, but may solve my basic problem.
if you ever decide to move to Ant 1.8 you can use following construction:
<import>
<javaresource name="resource_name.xml">
<classpath location="path_to_jar.jar" />
</javaresource>
</import>
I've posted an answer to the question that you've linked. I'll repeat a general solution here.
Reading Running Ant via Java, I think you can write a simple wrapper that will properly set a classpath and add any 3rd party library to the resulting class path.
Here I'm just cutting and pasting the sample from the above link with addition of the library to the classpath:
<java
classname="org.apache.tools.ant.launch.Launcher"
fork="true"
failonerror="true"
dir="${sub.builddir}"
timeout="4000000"
taskname="startAnt"
>
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
<pathelement location="/path/to/3rd-party-lib.jar"/>
</classpath>
<arg value="-buildfile"/>
<arg file="${sub.buildfile}"/>
<arg value="-Dthis=this"/>
<arg value="-Dthat=that"/>
<arg value="-Dbasedir=${sub.builddir}"/>
<arg value="-Dthe.other=the.other"/>
<arg value="${sub.target}"/>
</java>
I think you can even reuse the same build file by referencing ${ant.file}, just give a different target as an entry point.
EDIT
I think, this solution should only be used as a last resort measure. If task in general supports a <classpath> tag, then add required libraries locally to that specific task. Your gave a perfect example of this in your question with an ant-contrib taskdef.

Categories