AdoptOpenJDKのJava8でJavaFX8を使う方法
AdoptOpenJDKのJava8にOpenJFX8を自分でビルドして組み込んで使う方法
※ AdoptOpenJDK 8u181、Zulu 8u181の両方でも改めて試してみたが問題なく動作している。(2018/10/30)
※ (2018/11/21追記) Amazonが提供するビルド済みOpenJDKであるAmazon Corretto 8 (Amazon-Corretto-preview-8u192.msi)は、JavaFX8のバイナリも含んでいるため、そのまま、すぐにJavaFX8のアプリが動作する。(まだプレビュー版であるが、無料で製品に使えてJava8のサポート期間が2023年まである。)
概要
OpenJDKはオープンソースであるので誰でもビルドできるが、 ビルド済みバイナリを配布しているところとしては、以下のようなところがある。
- OracleビルドのOpenJDK
- AdoptOpenJDK
- IBM, Microsoftなどがスポンサーとなっている
- Java8以降のバイナリを提供する(Java8は32ビット、64ビットの両方あり)
- Java8, Java11の長期サポート(LTS)がある
- OpenJ9とHotspotのいずれかの仮想マシンを選べる
- JavaFXのバイナリは配布されていない
- AdoptOpenJDKのチケットにOpenJFXのビルドに対応したいというリクエストが出ていたようだが対応の見込みがあるかどうかは不明。(OpenJFX11がライブラリ化したので今更の必要性は低いだろう。)
- EclipseのPleiades All in One 2018-09版のJava環境として、JDK11にはAdoptOpenJDK11が採用されている。
- Azul Zulu
- Windows向けにはJava6(x86, x64), Java8(x86, x64)から利用可能, Java11はx64のみ
- ただしJavaFXのバイナリは配布されていない
- 無償版はCommunity Buildと呼ばれており、
Zulu builds of OpenJDK are free, downloadable versions of Java SE. All community builds of Zulu are free to download and use without restriction.
とあるので、利用者が自分でダウンロードして使う分には問題なさげ。 - Windows Azureクラウド環境ではZuluによるJavaのLTSサポートを受けられるので、サーバサイドJavaならAzureという選択肢もありかも
- Amazon Corretto (2018/11/21追記)
- Redhat OpenJDK Download
Java11からはJavaFXは、ただのライブラリになったので、JavaFX側がMavenのCentral Repositoryにjarを置いてくれていたりするので、 OpenJDK11でJavaFX11を使うのであればpom.xmlのdependencyに入れるだけの話である。
問題は、Java8のOpenJDK8でJavaFX8を使う場合である。
OpenJDKは、もともと当初よりOpenJFX(JavaFX)とは分離されているので、単にOpenJDKをビルドしただけではJavaFXは含まれていない。
- Oracleは、そもそもOpenJDK8のバイナリを配布していない。
- Redhatは、OpenJDK8, JavaFX8のバイナリを配布しているが、開発用途にしか使えない。
- AdoptOpenJDKは、OpenJDK8のバイナリを配布しているが、JavaFX8のバイナリを配布していない。
- Zuluも同様
結局、OpenJFXを自分でビルドするしかない。... と思ったけど、JavaFXを同梱する、Amazon Corretto が良いかも (2018/11/21追記)
となると、AdoptOpenJDKのOpenJDK8ビルドに対して、OpenJFX8を独自でビルドするのが良さそう、ということになる。
OpenJFXのビルド手順
Windowsでのビルド手順は(基本的には)OpenJFXのWikiに書かれている。
https://wiki.openjdk.java.net/display/OpenJFX/Building+OpenJFX+8u
(ただし、すでに記載が古いらしく、このとおりではない)
用意するもの
- Windows10 (もしくはWindows7でも可?)
- Visual Studio 2017 Professional (もしくは同等のCommunityでも可?)
- Cygwin
- Mercurial
- Gradle (4.10.2)
- Ant (1.10.5)
- JDK8のコピー
ビルドはCygwin上のBashから行え、という指示があるので、それに従う。
環境変数の設定
export JAVA_HOME="C:/Java/jdk1.8.0_151-nojfx" export ANT_HOME="C:/java/apache-ant-1.10.5" export GRADLE_HOME="C:/java/gradle-4.10.2" export PATH=$(cygpath -u $JAVA_HOME)/bin:$(cygpath -u $ANT_HOME)/bin:$(cygpath -u $GRADLE_HOME)/bin:$PATH export MSVC_VER="14.15.26726"
JAVA_HOME
は前述のとおり、OracleのJDK8から、JavaFX8のjfxrt.jarを取り除いたJDKを示す。
ANT_HOME
, GRADLE_HOME
は、ANTとGRADLEの場所を示す。
cygwinで動作するが、パスの形式はWindows形式のままとする。
PATH
には、cygwin形式のパスで指定する必要がある。
また、OpenJFX8のwikiには記載がないのだが、
環境変数MSVC_VER
で、Visual Studio 2017の現在のバージョンを指定する必要がある。
VS2017は大型アップデートするたびにバージョン番号がかわり、これによりVC++まわりのツールのフォルダ名が変わるっぽいので、マシン内に実在するバージョンを指定する必要がある。
たとえば、以下のようなフォルダがあることを確認する。
C:/Program Files (x86)/Microsoft Visual Studio/2017/Professional/VC/Tools/MSVC/14.15.26726/bin/HostX64/x64
(このあたりの実際のビルドの流れはOpenJFXのソースの rt/buildSrc/win.gradle
内にGroovyスクリプトで書かれているので、それを確認する。)
OpenJFX8のソースの入手
OpenJDKまわりはMercurialで管理されているので、以下のようにもらってくる。
hg clone http://hg.openjdk.java.net/openjfx/8u-dev/rt
なお、これで取れてくるソースのポジションがいまいち不明である。
(hg logで確認すると、もっとも近くのタグとしては8u202-b00 (Fri Jul 27 01:38:45 2018 +0000)
とかあるので、たぶん最新が取れてきているのだと思われる。
また、数字の進み具合からして、OpenJFX8のバージョンはOpenJDK8のバージョン番号とは直接の関係はなさそう。)
本来は、組み込み先となるJava8と、ビルドするOpenJFXのソースを、どのように合わせるのか、気にしなければならないとは思うのだが、
とりあえず、ここで取れたソースをもとに
Oracle Java8u151
(jfxrt.jarを取り除いたもの)を使用するJDKとしてビルドして- AdoptOpenJDKの
jdk8u172-b11(hotspot)
に生成された最新のOpenJFXバイナリ(8u202?
)を組み込む
という形でビルド・実行しても、うまく動作してくれているようだ。
ビルド
まず、Gradleが動作することを確認する。
java -version ant -version gradle -version
で、いずれもバージョンが表示できパスが通っていることを確認したら、
cd rt gradle tasks
rtフォルダ上でgradleのタスク一覧を確認させてみる。
gradle cleanAll
で初期化したのち、
gradle
でビルドを行う。
(VS2017のVC++からの警告は山ほど出るが、エラーは出ないはず。)
これで、OpenJFXのjar、exe, ネイティブライブラリ(DLL)等々一式がビルドされ、生成物は build
ディレクトリに作成される。
実際にJDKに組み込むのは、この下のsdk
の内容である。
なお、オプションとして
gradle.properties.template
ファイルをgradle.properties
にコピーして、
中のフラグをかえることでビルドする対象を変えられるようだが、通常、基本的には変える必要はなさそうである。
生成物の確認
私の環境では、ビルドしたjavafxpackager.exe
, javapackager.exe
が、生成した先からアンチウィルスによって隔離されてしまって戸惑った。(出来たと思ったら勝手にファイルが消えているので。)
もちろん、このアンチウィルスの誤判定だと思われる(別のアンチウィルスではひっかからなかった)ので、生成物が足りているか、隔離されていないかは見たほうが良いと思う。
私のところでは、以下のようなものが生成された。
build/sdk ├─bin │ javafxpackager.exe │ javapackager.exe │ ├─rt │ ├─bin │ │ api-ms-win-core-console-l1-1-0.dll │ │ api-ms-win-core-datetime-l1-1-0.dll │ │ api-ms-win-core-debug-l1-1-0.dll │ │ api-ms-win-core-errorhandling-l1-1-0.dll │ │ api-ms-win-core-file-l1-1-0.dll │ │ api-ms-win-core-file-l1-2-0.dll │ │ api-ms-win-core-file-l2-1-0.dll │ │ api-ms-win-core-handle-l1-1-0.dll │ │ api-ms-win-core-heap-l1-1-0.dll │ │ api-ms-win-core-interlocked-l1-1-0.dll │ │ api-ms-win-core-libraryloader-l1-1-0.dll │ │ api-ms-win-core-localization-l1-2-0.dll │ │ api-ms-win-core-memory-l1-1-0.dll │ │ api-ms-win-core-namedpipe-l1-1-0.dll │ │ api-ms-win-core-processenvironment-l1-1-0.dll │ │ api-ms-win-core-processthreads-l1-1-0.dll │ │ api-ms-win-core-processthreads-l1-1-1.dll │ │ api-ms-win-core-profile-l1-1-0.dll │ │ api-ms-win-core-rtlsupport-l1-1-0.dll │ │ api-ms-win-core-string-l1-1-0.dll │ │ api-ms-win-core-synch-l1-1-0.dll │ │ api-ms-win-core-synch-l1-2-0.dll │ │ api-ms-win-core-sysinfo-l1-1-0.dll │ │ api-ms-win-core-timezone-l1-1-0.dll │ │ api-ms-win-core-util-l1-1-0.dll │ │ api-ms-win-crt-conio-l1-1-0.dll │ │ api-ms-win-crt-convert-l1-1-0.dll │ │ api-ms-win-crt-environment-l1-1-0.dll │ │ api-ms-win-crt-filesystem-l1-1-0.dll │ │ api-ms-win-crt-heap-l1-1-0.dll │ │ api-ms-win-crt-locale-l1-1-0.dll │ │ api-ms-win-crt-math-l1-1-0.dll │ │ api-ms-win-crt-multibyte-l1-1-0.dll │ │ api-ms-win-crt-private-l1-1-0.dll │ │ api-ms-win-crt-process-l1-1-0.dll │ │ api-ms-win-crt-runtime-l1-1-0.dll │ │ api-ms-win-crt-stdio-l1-1-0.dll │ │ api-ms-win-crt-string-l1-1-0.dll │ │ api-ms-win-crt-time-l1-1-0.dll │ │ api-ms-win-crt-utility-l1-1-0.dll │ │ decora_sse.dll │ │ fxplugins.dll │ │ glass.dll │ │ glib-lite.dll │ │ gstreamer-lite.dll │ │ javafx_font.dll │ │ javafx_iio.dll │ │ jfxmedia.dll │ │ jfxwebkit.dll │ │ prism_common.dll │ │ prism_d3d.dll │ │ prism_es2.dll │ │ prism_sw.dll │ │ ucrtbase.dll │ │ │ └─lib │ │ javafx.properties │ │ jfxswt.jar │ │ │ └─ext │ jfxrt.jar │ └─lib ant-javafx.jar javafx-mx.jar packager.jar
rtはjre
にリネームして、あとは AdoptOpenJDKのjdk8u181-b13-hotsopt
に上書きすればよい。
簡単なテスト
以下のようなシステムプロパティを表示する簡単なJavaFXのコードを実行してみる。
これはJavaFXでステージを作成してシステムプロパティを表示するだけのものである。
システムプロパティwebview
がtrueの場合は、javafx.scene.web.WebView
を使った表示も行う。
package jp.seraphyware.example; import java.util.Properties; import java.util.TreeSet; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.TextArea; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import javafx.scene.web.WebEngine; import javafx.scene.web.WebView; import javafx.stage.Stage; public class SimpleJavaFX8Example extends Application { private Stage stg; @Override public void start(Stage stg) throws Exception { this.stg = stg; stg.setTitle(getClass().getSimpleName()); VBox box = new VBox(); if (Boolean.getBoolean("webview")) { WebView wv = new WebView(); WebEngine engine = wv.getEngine(); StringBuilder buf = new StringBuilder(); buf.append("<table>"); Properties props = System.getProperties(); for (String name : new TreeSet<>(props.stringPropertyNames())) { String val = props.getProperty(name); val = val.replace("&", "&").replace("<", "<"); buf.append("<tr><td>").append(name).append("</td><td>").append(val).append("</td></tr>"); } buf.append("</table>"); engine.loadContent("<title>t</title><h1>System Properties</h1>" + buf.toString(), "text/html"); box.getChildren().add(wv); VBox.setVgrow(wv, Priority.ALWAYS); } TextArea textarea = new TextArea(); textarea.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); { StringBuilder buf = new StringBuilder(); Properties props = System.getProperties(); for (String name : new TreeSet<>(props.stringPropertyNames())) { String val = props.getProperty(name); buf.append("*").append(name).append("=").append(val).append("\r\n"); } textarea.setText(buf.toString()); } box.getChildren().add(textarea); VBox.setVgrow(textarea, Priority.ALWAYS); stg.setScene(new Scene(box)); stg.show(); } public static void main(String[] args) { launch(args); } }
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jp.seraphyware.example</groupId> <artifactId>javafx8example</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <mainClass>jp.seraphyware.example.SimpleJavaFX8Example</mainClass> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <manifest> <mainClass>${mainClass}</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build> </project>
実行結果
Windows10上のPowerShellで実行
$env:PATH="C:\Java\jdk8u181-b13-hotsopt-openjfx\bin;C:\Windows\System32;C:\Windows" java -Dwebview=true -jar .\target\javafx8example-0.0.1-SNAPSHOT.jar
とりあえず動作しているようである。
Azul Zulu
zulu8.31.0.1-jdk8.0.181-win_i686 (32bit) に OpenJFX8を入れた場合
Windows10上のPowerShellで実行
$env:PATH="C:\java\zulu8.31.0.1-jdk8.0.181-win_i686-openjfx\bin;C:\Windows\System32;C:\Windows" java -Dwebview=true -jar .\target\javafx8example-0.0.1-SNAPSHOT.jar
こちらも問題なく動作しているようである。
また、バージョン番号等はAdoptOpenJDKのものよりも、Oracleのものに近いような感じである。
AdoptOpenJDKは8u181になってから java.version
は、Zuluと同等のものに修正されたようだ。(2018/10/30追記)
(cacertsが空というバグもない。)AdoptOpenJDKの8u181ではcacertsが空の問題は修正された模様。(2018/10/30追記)
さすが商用レベルのOpenJDKビルドらしく、信頼性などの点で、Zuluは優れていそうである。
注意点
VS2013でDirectX SDKを入れてビルドを試みたところ、一応、ビルドは成功し、JavaFXの組み込みも成功したかに見えたが、
WebView
の呼び出しに失敗した。(UnsatisfiedLinkError例外)- Windows10マシンのVS2017でビルドしなおしたところ、この問題は解消した。
- VS2013でのビルドが不味いのか、WebViewがリンクできてなかった原因はいまいち不明である。
- Windows10マシンのVS2017でビルドしなおしたところ、この問題は解消した。
VS2017でビルドとしたOpenJFXバイナリを
AdoptOpenJDK jdk8u181-b13_openj9
に組み込んだところ、WebView等々すべて善く動いているようにみえたが、ControlsFXのSpreadsheetView
の表示中に(確実に)セグメンテーションエラーが発生してJVMが落ちる。- OpenJ9ではない、
AdoptOpenJDK jdk8u172-b11(hotspot)
であれば、問題は起きないっぽい。- 原因がOpenJ9仮想マシンなのか、OpenJFXなのか、それともビルド方法が不味いのか、バージョン不一致なのか、そのあたりの原因は不明である。
- OpenJ9ではない、
こんな感じのエラーを吐いてOpenJ9 JVMが死ぬ。
Unhandled exception Type=Segmentation error vmState=0x0002000f Windows_ExceptionCode=c0000005 J9Generic_Signal=00000004 ExceptionAddress=000007FEF82D87B9 ContextFlags=0010001f
また、OpenJFXとは直接関係はないが、
- OpenJDKのバイナリごとにバージョン表記が違うので、たとえば、システムプロパティでjava1.8.0_60
以降 であるか? といった判定をしていると正しく動作しない可能性が高い。
- Windows版のAdoptOpenJDK jdk8u172-b11
(hotspot/j9とも)はルート証明書が格納されているはずの cacertsが空なので、HTTPS通信ができない。(いずれ直ると思うけど)
- これは軽微な問題で、さしあたり、/jre/lib/security/cacerts
を、ちゃんとルート証明書の入ったjksファイルに置き換えれば使える。
これらの問題はAdoptOpenJDK 8u181では修正済みである。(2018/10/30追記)
結論
WindowsでのOpenJFX8のビルドそのものは、VS2017 Professional が入っていれば、それほど難しくはない感じである。
AdoptOpenJDKのOpenJDK8(Hotspot)に、OpenJFXの自前ビルドの組み込み方は分かったので、 とりあえず、WindowsのJava8クライアント環境も、しばらく(2019/1以降も)延命できるかもしれない。