javac source and target options
Solution 1:
- source: The version that your source code requires to compile.
- target: The oldest JRE version you want to support.
Be sure to also set bootclasspath to ensure your program will work on older VMs.
From the javac
documentation:
Cross-Compilation Example
The following example uses javac to compile code that will run on a 1.6 VM.
C\:>javac -source 1.6 -target 1.6 -bootclasspath C:\jdk1.6.0\lib\rt.jar -extdirs "" OldCode.java
The
-source 1.6
option specifies that version 1.6 (or 6) of the Java programming language be used to compileOldCode.java
. The option-target 1.6
option ensures that the generated class files will be compatible with 1.6 VMs. Note that in most cases, the value of the-target
option is the value of the-source
option; in this example, you can omit the-target
option.You must specify the
-bootclasspath
option to specify the correct version of the bootstrap classes (thert.jar
library). If not, the compiler generates the following warning:C:\>javac -source 1.6 OldCode.java warning: [options] bootstrap class path not set in conjunction with -source 1.6
If you do not specify the correct version of bootstrap classes, the compiler will use the old language rules (in this example, it will use version 1.6 of the Java programming language) combined with the new bootstrap classes, which can result in class files that do not work on the older platform (in this case, Java SE 6) because reference to non-existent methods can get included.
Solution 2:
Java is backwards compatible. You use the -source option to specify the java version used for compilation and you use the -target option to specify the lowest java version to support. eg. If I specify a target of 1.4, then my program will not be able to run on java 1.3 or lower. see the following javac documentation for more info. especially the section on Cross-Compilation Options
Solution 3:
Peter Tseng does mention a lot of key points to remember during compilation. As a matter of fact even I faced a similar issue sometime back and want to share the root causes of many issues.
I had a source code which had to compiled & make it compatible (-source & -target) Java '1.8'. The code itself had
- Lot of Trademark symbol hence I ended up in unrecognized characters(I had to tweak the IntelliJ Idea's encoding settings)
- Lot of changes to
java.sql.*
package - Usage of lot of third-party libraries. Spare me the horror of explaining the difficulty debugging there and blah blah blah.
After certain changes I ended up with a code which had equal amount of JUnit test cases to run. Eventually I bumped into a java.lang.VerifyError
. I was shocked when I understood that such error happens when I compile and run the code in the different libraries/environment(Which was not the case).
What I almost missed was that, for honoring the fact that the tests had to run in an isolated environment, the Junit & its test cases where executed in a seperate forked VM
<target name="runJunit">
<junit printonsummary="on"
haltonfailure="off"
fork="true"
forkmode="once">
<formatter />
<batchtest />
<classpath />
</junit>
</target>
This obviously will be spanned as a separate process and act as a standalone application in execution. Even though the IDE spans both processes synchronously, the JVM's are pretty much isolated.
After Java 1.7, Oracle has introduced a stricter verification and changed the class format a bit -- to contain a stack map, used to verify that code is correct. The exception I had seen was because some method doesn't have a valid stack map. I eventually tried including lot of JVM options to tweak the setting, but in vain.
<jvmarg value="bootclasspath:{env.JAVA_HOME}\jre\bin\rt.jar" prefix="-X"/>
nothing worked. The only work around was to include
<jvmarg value=":UseSplitVerifier" prefix="-XX"/>
In Java 1.7 to allow only nominal byte code verification. Since this was taken off in Java 1.8, the only option was to use
<jvmarg value="-noverify"/>