Can standard Sun javac do incremental compiling? - java

Recently I started to use Eclipse's java compiler, because it is significantly faster than standard javac. I was told that it's faster because it performs incremental compiling. But I'm still a bit unsure about this since I can't find any authoritative documentation about both - eclispse's and sun's - compilers "incremental feature". Is it true that Sun's compiler always compiles every source file and Eclipse's compiler compile only changed files and those that are affected by such a change?
Edit: I'm not using Eclipse autobuild feature but instead I'm setting
-Dbuild.compiler=org.eclipse.jdt.core.JDTCompilerAdapter
for my ant builds.

Is it true that Sun's compiler always compiles every source file and Eclipse's compiler compile only changed files and those that are affected by such a change?
I believe that you are correct on both counts.
You can of course force Eclipse to recompile everything.
But the other part of the equation is that Java build tools like Ant and Maven are capable of only compiling classes that have changed, and their tree of dependent classes.
EDIT
In Ant, incremental compilation can be done in two ways:
By default the <javac> task compares the timestamps of .java and corresponding .class files, and only tells the Java compiler to recompile source (.java) files that are newer than their corresponding target (.class) files, or that don't have a target file at all.
The <depend> task also takes into account dependencies between classes, which it determines by reading and analysing the dependency information embedded in the .class files. Having determined which .class files are out of date, the <depend> task deletes them so a following <javac> task will recompile them. However, this is not entirely fool-proof. For example, extensive changes to the source code can lead to the <depend> task may be analysing stale dependencies. Also certain kinds of dependency (e.g. on static constants) are not apparent in the .class file format.
To understand why Ant <depend> is not fool-proof, read the "Limitations" section of the documentation.

Javac only compiles source files that are either named on the command line or are dependencies and are out of date. Eclipse may have a finer-grained way of deciding what that means.

Eclipse certainly does this. Also it does it at save time if you have that option turned on (and it is by default). It looks like sun also doesn't do this (it is very easy to test, just make a small project where A is the main class that uses class B, but B doesn't use class A. Then change A and compile the project again, see if the timestamp for b.class has changed.
This is the way many compilers work (also gcc for instance). You can use tools like ant and make to compile only the part the project that has changed. Also note that these tools aren't perfect, sometimes eclipse just loses track of the changes and you'll need to do a full rebuild.

Restating what I've heard here and phrasing it for lazy folks like me:
You can achieve incremental builds with the javac task in ant, but you should use the depend task to clear out .class files for your modified .java AND you must not leave the includes statement unspecified in the javac task. (Specifying just src path in the javac task and leaving includes unspecified causes javac recompile all sources it finds.)
Here are my depends and javac tasks. With the standard Oracle java compiler, only .java files I modify are compiled. Hope this helps!
<depend srcdir="JavaSource" destdir="${target.classes}" cache="${dependencies.dir}" closure="yes">
<classpath refid="compiler.classpath" />
<include name="**/*.java"/>
</depend>
<javac destdir="${target.classes}" debug="true" debuglevel="${debug.features}" optimize="${optimize.flag}" fork="yes" deprecation="no" source="1.6" target="1.6" encoding="UTF-8" includeantruntime="no">
<classpath refid="compiler.classpath"/>
<src path="JavaSource"/>
<include name="**/*.java" /> <!-- This enables the incremental build -->
</javac>

Related

Ignore minor errors using javadoc

I'm trying to generate the documentation, using javadoc, from one or two downloaded jar files (with the source of course, after having extracted everything).
But using javadoc, even in an Ant file, I'm being prevented from generating this because of silly things, specifically "package XXX does not exist" and "cannot find symbol"... I just want javadoc to put the text of these things (external references) in the html docs, but to document all the .java files it finds...
NB for anyone interested this is the download page with the download files (containing source) from which I'm trying to generate the API documentation: http://logback.qos.ch/download.html
Following Mark Rotteveel's help, my Ant build file now looks like this:
<?xml version="1.0" ?>
<project name="document logback core" default="doc">
<target name="doc">
<mkdir dir="javadoc" />
<property name="excludedPackages"
value="org.codehaus.*,javax.mail.*"/>
<javadoc destdir="javadoc" sourcepath="src" packagenames="main.*"
excludepackagenames="${excludedPackages}"
additionalparam="-Xdoclint:none" />
</target>
</project>
... but it still gives errors 1) about packages not being found, including "org.codehaus.[xxx...]" and "javax.mail.[xxx...]" and 2) about symbols not being found (although this may go away if I can solve the missing packages errors).
NB the build is said to be successful, but I get complaints about no source files being found (where there are indeed commented .java files), and no html at all is generated under \javadoc.
later, following Tony Pierce's success in generating these docs
Installed Ant 1.9.6, changed path accordingly, checked to make sure this was the version being used... tried again. Failed again. This was the end of my output:
[javadoc]
D:\Desktop\Downloads\logback-1.1.7.tar\logback-1.1.7\logback-core\src\test\java\ch\qos\logback\core\appender\ConsoleAppenderTest.java:32:
error: package org.junit does not exist [javadoc] import static
org.junit.Assert.assertEquals; [javadoc]_______________________^
[javadoc] javadoc: error - No public or protected classes found to
document. [javadoc] 1 error [javadoc] 100 warnings
BUILD SUCCESSFUL Total time: 2 seconds
It does create the javadoc folder... but this is empty.
NB about the above "package does not exist" error (there were many others): this one is particularly mystifying as I thought Ant somehow included junit by default (NB I am a complete newbie at Ant, just working through "Ant in Action").
But... with the Ant javac task you can set includeAntRuntime="true" ... according to this book that makes Ant's own junit.jar be included. Unfortunately the javadoc task doesn't support this attribute.
later still
My thinking was a bit muddled on this, to be honest: the simplest way I have found to compile javadocs from third-party source jars is just by extracting and then using the command line, typically:
javadoc -d docs -Xmaxwarns 10 -Xmaxerrs 10 -Xdoclint:none -sourcepath
. -subpackages ch.qos.logback.core
... as for javadoc for one's own code this doesn't seem to be a problem in Gradle (I was only glimpsing at Ant, aware that the future is Gradle... and it's not particularly difficult to get to grips with the basics).
NB If you install the Gradle STS plugin for Eclipse, and then create a new project using Gradle STS wizard your build file contains the line
apply plugin: 'eclipse'
... one of the effects of which is that by default the source as well as the executables for all your third-party dependencies will be downloaded under GRADLE_HOME during the build. Pretty good!
Java 8 introduced doclint which will treat certain problems as an error and not produce the documentation. It is possible to disable this by specifying the commandline option -Xdoclint:none.
See also: Turning off doclint in JDK 8 Javadoc
Eg in Ant you would need to do add a additionalparam="-Xdoclint:none" attribute to the javadoc task. A (slightly modified) example from Jaybird:
<target name="javadocs" depends="init,set-driver-sources">
<mkdir dir="${build.docs}"/>
<javadoc destdir="${build.docs}"
author="true"
version="true"
windowtitle="${Name} API"
doctitle="${Name}"
extdirs="${module.thirdparty}"
additionalparam="-Xdoclint:none"
excludepackagenames="${excludedPackages}"
bottom="Copyright © 2001-2015 Jaybird (Firebird JDBC/JCA) team. All rights reserved.">
<arg line="${java.module.arg}"/>
<classpath refid="javac.driver.classpath"/>
<sourcepath>
<pathelement path="${source.java}"/>
<pathelement path="${source.jna-client}"/>
</sourcepath>
<sourcepath refid="source.java.openoffice"/>
<sourcepath refid="source.java.additional"/>
<link href="http://docs.oracle.com/javase/7/docs/api/"/>
</javadoc>
</target>
Compile Errors With Custom Doclet with Java 9 or later
The -Xdoclint:none is an option of the standard doclet which will not work for custom doclets.
If you have a custom doclet and don't care about compilation errors, you can pass the --ignore-source-errors option either to the javadoc command line tool or to javax.tools.DocumentationTool.getTask(...) if you invoke your doclet programmatically.
The --ignore-source-errors option is not documented. Maybe because it might be removed in future. The clean way is to add all required libraries to the classpath (via the -classpath option to actually resolve the compilation errors).
I simplified your build file a bit and built the javadoc successfully. Here's what I did:
Downloaded the logback zip
Expanded the sources jars inside into a src directory
Ran ant 1.9.6 under java 8 with this:
<?xml version="1.0" ?>
<project name="document logback core" default="doc">
<target name="doc">
<mkdir dir="javadoc" />
<javadoc destdir="javadoc" sourcepath="src"
additionalparam="-Xdoclint:none" />
</target>
</project>
It produced a lot of warnings, but created a javadoc directory filled with html.
I removed excludepackagenames and dropped the packagenames element. In any case, packagenames="main.*" prevents the javadoc generation because the only root packages in the jar are ch and org.

Ant build -- optionally override location of java executable

I have several java projects on the same machine which really need to be built with different java compilers, one with java 1.6 and one with java 1.7. (No, it's not sufficient to build them with the higher version of java and specify source and target for the project that requires the lower version-- the differences between them produce test failures).
My colleagues do not have this problem -- they have only one project that requires 1.6. I would like to put in some configuration that enables me to override the java compiler without requiring them to add environment variables. I'm imagining something like this:
<javac executable='${java.executable.path}' srcdir='${src.dir}' destdir='${dest.dir.classes}' source='1.6' target='1.6' fork='true' />
where ${java.executable.path} is defined earlier in the file as:
<condition property="java.executable.path" value="${env.PROJ_JAVA_HOME}" else="${DEFAULT_JAVAC}">
<isset property="env.PROJ_JAVA_HOME" />
</condition>
except... there is no ${DEFAULT_JAVAC} that I can find. Is there a better way to do this that I'm missing? Or is ant just not built for things like this?
you could default to whatever javac is on the path.
its possible to set an ant property by executing a shell script, so you'll need to execute something like which javac

All warnings as errors with the Eclipse Java compiler (3.6.2)

How do I treat warnings as errors with the Eclipse Java compiler (ECJ) 3.6.2* when running from the command-line?
Newer versions (at least, 3.8.2) have the -err:all flag, however this isn't available in 3.6.2. Do I have any other options?
I've found this question (Javac: Treat warnings as errors) which recommends the undocumented -Werror flag, but that only seems to work for javac.
Note: For various reasons completely out of my control, I must use ECJ 3.6.2. So switching to a newer version or javac is not an option (at least, not in the immediate future)!
* Also seems to be known as the "JDT Core Batch Compiler".
I don't think there's a way to specify err:all, but there's a decent workaround:
Create an eclipse project.
Project > Properties > Java Compiler > Errors / Warnings.
Enable project specific settings.
Set everything to Error level by hand (annoying, but a one time operation).
That generates a org.eclipse.jdt.core.prefs file.
Use the project/.settings/org.eclipse.jdt.core.prefs file in your compile process.
Here's an example using ant:
<javac srcdir="${test-unit.dir}" destdir="${target-test-classes.dir}"
classpathref="test.classpath" source="1.6" target="1.6" debug="true"
includeAntRuntime="false" compiler="org.eclipse.jdt.core.JDTCompilerAdapter">
<compilerclasspath location="./libs/ecj-3.7.2.jar" />
<compilerarg line="-time -properties .settings/org.eclipse.jdt.core.prefs" />
</javac>

Best practice for code modification during ant build

Admitted, this doesn't sound like a best practice altogether, but let me explain. During the build, we need to paste the build number and the system version into a class whose sole purpose is to contain these values and make them accessible.
Our first idea was to use system properties, but due to the volatility of the deployment environment (an other way of saying "the sysadmins are doing weird unholy creepy things") we would like to have them hard-coded.
Essentially I see 4 possibilities to achieve it in ant :
use <replace> on a token in the class
The problem with this approach is that the file is changed, so you have to replace the token back after compilation with a <replaceregexp>...sooo ugly, I don't want to touch source code with regex. Plus temporal dependencies.
copy the file, make replace on the copy, compile copy, delete copy
One one has to mind the sequence - the original class has to be compiled first in order to be overwritten by the copy. Temporal dependencies are ugly too.
copy the file, replace the token on the original, compile, replace the stained original with the copy
Same temporal dependency issue unless embedded in the compile target. Which is ugly too, because all our build files use the same imported compile target.
create the file from scratch in the build script / store the file outside the source path
Is an improvement over the first three as there are no temporal dependencies, but the compiler/IDE is very unhappy as it is oblivious of the class. The red markers are disturbingly ugly.
What are your thoughts on the alternatives?
Are there any best practices for this?
I sure hope I have missed a perfectly sane approach.
Thank you
EDIT
We ended up using the manifest to store the build number and system version in the Implementation-Version attribute, unsing MyClass.class.getPackage().getImplementationVersion(). I have found this solution was one of the answers to this thread, which was posted in the comment by andersoj
I think a simpler approach would be to have your Version.java class read from a simple .properties file included in the JAR, and just generate this .properties file at build-time in the Ant build. For example just generate:
build.number = 142
build.timestamp = 5/12/2011 12:31
The built-in <buildnumber> task in Ant does half of this already (see the second example).
#2 is generally the way I've seen it done, except that your not-ready-to-compile sources should be in a separate place from you ready-to-compile sources. This avoids the temporal issues you talk about as it should only be compiled once.
This is a common pattern that shows up all the time in software build processes.
The pattern being:
Generate source from some resource and then compile it.
This applies to many things from filtering sources before compilation to generating interface stubs for RMI, CORBA, Web Services, etc...
Copy the source to a designated 'generated sources' location and do the token replacement on the copies files to generate sources, then compile the generated sources to your compiled classes destination.
The order of compilation will depend on whether or not your other sources depend on the generated sources.
My solution would be to:
use on a token in the class:
<replace dir="${source.dir}" includes="**/BuildInfo.*" summary="yes">
<replacefilter token="{{BUILD}}" value="${build}" />
<replacefilter token="{{BUILDDATE}}" value="${builddate}" />
</replace>
This replacement should only take place in the build steps performed by your build system, never within a compile/debug session inside an IDE.
The build system setup should not submit changed source code back to the source repository anyway, so the problem of changed code does not exist with this approach.
In my experience it does not help when you place the build information in a property file, as administrators tend to keep property files while upgrading - replacing the property file that came out of the install. (Build information in a property file is informational to us. It gives an opportunity to check during startup if the property file is in synch with the code version.)
I remember we used the 4th approach in a little different way. You can pass release number to the ant script while creating a release.Ant script should include that in the release(config/properties file) and your class should read it from there may be using properties file or config file.
I always recommend to create some sort of directory and put all built code there. Don't touch the directories you checked out. I usually create a target directory and place all files modified and built there.
If there aren't too many *.java files (or *.cpp files), copy them to target/source' and compile there. You can use thetask with a` to modify this file one file with the build number as you copy it.
<javac srcdir="${target.dir}/source"
destdir="${target.dir}/classes"
[yadda, yadda, yadda]
</java>
This way, you're making no modification in the checked out source directory, so no one will accidentally check in the changes. Plus, you can do a clean by simply deleting the target directory.
If there are thousands, if not millions of *.java files, then you can copy the templates to target/source and then compile the source in both {$basedir}/source and target/source. That way, you're still not mucking up the checked out code and leaving a chance that someone will accidentally check in a modified version. And, you can still do a clean by simply removing target.
I was looking for a solution to the same problem, reading this link: http://ant.apache.org/manual/Tasks/propertyfile.html I was able to findout the solution.
I work with netbeans, so I just need to add this piece of code to my build.xml
<target name="-post-init">
<property name="header" value="##Generated file - do not modify!"/>
<propertyfile file="${src.dir}/version.prop" comment="${header}">
<entry key="product.build.major" type="int" value="1" />
<entry key="product.build.minor" type="int" default="0" operation="+" />
<entry key="product.build.date" type="date" value="now" />
</propertyfile>
</target>
This will increment the minor version each time yo compile the project with clean and build. So you are save to run the project any time that the minor version will stay still.
And I just need to read the file in Runtime. I hope this help.

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.

Categories