「どの JDK ディストリビューションで `javac -source 1.6 -target 1.5` を実行できますか?」で説明されているようなコンパイル オプションを見てきました。. ソースとターゲットの個々のオプションを理解しています。ソース バージョンがターゲット バージョンよりも高い理由がわかりません。古いターゲット用のコードをコンパイルすることは理にかなっています。しかし、その場合、実行できるようにしたい最も古いターゲットの -source を使用しないでください。
4 に答える
- source: ソース コードのコンパイルに必要なバージョン。
- target: サポートする最も古い JRE バージョン。
プログラムが古い VM で確実に動作するように、必ず bootclasspath も設定してください。
javac
ドキュメントから:
クロスコンパイルの例
次の例では、javac を使用して、1.6 VM で実行されるコードをコンパイルします。
C\:>javac -source 1.6 -target 1.6 -bootclasspath C:\jdk1.6.0\lib\rt.jar -extdirs "" OldCode.java
この
-source 1.6
オプションは、Java プログラミング言語のバージョン 1.6 (または 6) を使用して をコンパイルすることを指定しますOldCode.java
。オプション-target 1.6
オプションは、生成されたクラス ファイルが 1.6 VM と互換性があることを保証します。-target
ほとんどの場合、オプションの値はオプションの値であることに注意してください-source
。この例では、オプションを省略-target
できます。オプションを指定して、ブートストラップ クラス (ライブラリ)
-bootclasspath
の正しいバージョンを指定する必要があります。rt.jar
そうでない場合、コンパイラは次の警告を生成します。C:\>javac -source 1.6 OldCode.java warning: [options] bootstrap class path not set in conjunction with -source 1.6
正しいバージョンのブートストラップ クラスを指定しない場合、コンパイラは古い言語規則 (この例では Java プログラミング言語のバージョン 1.6 を使用します) を新しいブートストラップ クラスと組み合わせて使用します。存在しないメソッドへの参照が含まれる可能性があるため、古いプラットフォーム (この場合は Java SE 6) では機能しません。
Java は下位互換性があります。-sourceオプションを使用してコンパイルに使用する Java バージョンを指定し、-targetオプションを使用してサポートする最も低い Java バージョンを指定します。例えば。1.4 のターゲットを指定すると、プログラムは Java 1.3 以下で実行できなくなります。詳細については、次の javacドキュメントを参照してください。特にクロスコンパイルオプションのセクション
Peter Tseng は、コンパイル時に覚えておくべき多くの重要なポイントについて言及しています。実際のところ、私でさえ以前に同様の問題に直面したことがあり、多くの問題の根本原因を共有したいと考えています.
コンパイルして互換性を持たせる必要があるソースコードがありました (-source & -target) Java '1.8'。コード自体には
- 多くの商標記号があるため、認識できない文字になってしまいました (IntelliJ Idea のエンコーディング設定を微調整する必要がありました)。
java.sql.*
パッケージの変更点が多い- 多くのサードパーティ ライブラリの使用。そこでのデバッグの難しさを説明する恐怖を私に惜しまないでください。
特定の変更の後、実行するJUnitテストケースが同じ量のコードになりました。最終的に私はにぶつかったjava.lang.VerifyError
。異なるライブラリ/環境でコードをコンパイルして実行すると、このようなエラーが発生することを理解したとき、私はショックを受けました(そうではありませんでした)。
私がほとんど見逃していたのは、テストを隔離された環境で実行しなければならなかったという事実を尊重するために、Junit とそのテスト ケースが別のフォークされた VM で実行されたことです。
<target name="runJunit">
<junit printonsummary="on"
haltonfailure="off"
fork="true"
forkmode="once">
<formatter />
<batchtest />
<classpath />
</junit>
</target>
これは明らかに別のプロセスとしてスパンされ、実行中のスタンドアロン アプリケーションとして機能します。IDE は両方のプロセスに同時にまたがっていますが、JVM はほぼ分離されています。
Java 1.7 の後、Oracle はより厳密な検証を導入し、クラス形式を少し変更しました。コードが正しいことを検証するために使用されるスタック マップを含めるためです。私が見た例外は、一部のメソッドに有効なスタック マップがないためです。最終的に、設定を微調整するために多くの JVM オプションを含めようとしましたが、無駄でした。
<jvmarg value="bootclasspath:{env.JAVA_HOME}\jre\bin\rt.jar" prefix="-X"/>
何も機能しませんでした。唯一の回避策は、含めることでした
<jvmarg value=":UseSplitVerifier" prefix="-XX"/>
Java 1.7 では、公称バイト コードの検証のみを許可します。これは Java 1.8 で廃止されたため、唯一のオプションは使用することでした。
<jvmarg value="-noverify"/>