日曜プログラミング

休日趣味でやってるプログラミング関連記事をダラダラと

Clojure + JavaFX プログラムを配布できないものか試してみる

[2014-05-08] 手順一部更新

Github を使いだしたので慣れる為にも今回からはてブロでも対応してる Markdown 記法で記事を書くことにする。まあ見た目には変わらないんだけど。

さて、これまでしつこく JavaFX を試してたのだが、気にはしつつもほったらかしていた配布をどうしようかと言うのをそろそろ調べてみる事にする。

配布形態

デスクトップアプリとして

想定環境

JavaFX ランタイムを含む JRE は入っているものとする。言い換えると作った JavaFX プログラムに JavaFX ランタイム(jfxrt.jar)は含めたくない。

手順概要

  1. JavaFX の project.clj に :provided 指定をする
  2. lein compile
  3. clojure-1.5.1.jar を target へ展開
  4. javafxpackager で jar に固める

leiningen の :provided 指定

leiningen の uberjar は単体で完結する Java アプリを配布するにはお手軽なんだが、外部フレー ムワークの方で依存性を解決してくれるから別に含めてくれなくてもいいのにな、と言う環境へ配布 する場合には :provided 指定が使える。

これ 2.0.0-preview10 から対応してたのね。 公式チュートリアル にはあるんだが サンプル project.clj にはなかったから見逃してたなあ。

今回の目的は配布できるかどうかと言う所なのでプログラムは hello world 程度で OK。つか 以前の記事で紹介したのを使いまわす。 そういや単純 uberjar だとサイズがエラいことになるからどうしようかで止まったままだったのをリンク貼って思い出したw

話を戻すと leiningen の :provided 指定は実際にはこんな感じで uberjar 時に含めたくないのをこちらに書く。

  ;; これ
  :profiles {:provided
             {:dependencies
              [[local.oracle/javafxrt "2.2.45"]]}}

通常の :dependencies には重複して書かない事。

これで lein run までは動く。続けて読んでる人とか少ないと思うので一応言っておくと、 この leiningen 設定は maven ローカルリポジトリ(.m2 フォルダ)に JavaFX ランタイムを入れてるのを前提で話してるので注意。 やり方はこちら

lein compile

jar に固めるのではなく class ファイルを作るだけにとどめる為 lein compile で終わらせる。 詳しくは後述するが jar に固めるのは javafxpackager にやらせる。

[2014-05-08 追加] AOT 指定されてない ns は lein compile だけだと class ファイルが作られないので lein compile :all とした方が良さそう。

clojure-1.5.1.jar を target フォルダへ展開

javafxpackager は leiningen 設定を見てくれる訳ではないので、clojure 本体の jar を展開する。 この時 clojure の本体に含まれる MANIFEST.MF とかのファイルは消して clojure のフォルダだけ にしておく。

以上は leiningen のデフォルト project.clj 設定である事前提で話してるが、 :dependencies や class を生成してる場所を変えている場合は適当に読み替えて下さい。

[2014-05-08 追加]

最初の記事作成時は dependencies が JavaFXClojure のみ前提で話してるが、 他に外部ライブラリ追加した場合も同じ。

もう少し具体的に言うと、

  1. 指定 Group ID, Artifact ID, Version に該当する .m2 フォルダパス下 jar ファイルを leiningen プロジェクトの target\classes 以下に展開する。
  2. jar ファイルを一通り展開後、META-INF フォルダを削除する。 複数 jar ファイル展開時は META-INF フォルダは各ライブラリの jar に含まれてるが気にせず上書きして良い。

javafxpackager で jar に固める

コマンドはこんな感じ。

javafxpackager -createjar ^
 -appclass fxhello.core ^
 -srcdir target\classes ^
 -outdir target ^
 -outfile fxhello.jar

補足すると ^ は Windows コマンドプロンプトのエスケープ文字。これで改行をエスケープできる。

-createjar でどうも jar に固める時に JavaFX アプリとして起動させるためのランチャークラスを埋め込むみたい。

以上で target フォルダ以下に出来た fxhello.jar をダブルクリックすると起動する。

[2014-05-08 追加]

手順更新後、手前味噌だが自分で作った cljfx を含めても動いたのを確認。という訳で課題としていた一つは片付いた。 サイズは約 6MB で JavaFX Runtime 込みの 20MB に比べたらだいぶ小さくなった。

また、できた jar ファイル展開してみたが、MANIFEST.MF がこんな感じになってて、 どうも元々の main 起動前に JavaFX Packager の Main が差し込まれるようになってる雰囲気。

  Manifest-Version: 1.0
  JavaFX-Version: 2.2
  JavaFX-Application-Class: semmt.core
  Created-By: JavaFX Packager
  Main-Class: com/javafx/main/Main

ここで JavaFX ランタイムを読めるようなんやかやしてるのかな。javap で Main-Class の一覧見たけど良く分からん。

課題

  • 自分が今ちまちまやってるcljfx(仮名)と組み合わせていけるんだろうか
    • [2014-05-08] 追記分で確認済
  • 上が確認できれば leiningen プラグイン化の検討も有りか(作ったことないが)

まとめ

もともと Java8 への移行が済んでしまえば不要になってくる手順だとは思う。

とは言え Java8 もまだ正式リリースされたわけではないし、リリースされたからと言って一斉に皆 移行する訳でもないので、JavaFX + Clojure でデスクトップアプリを作りたいと言う人にはちょっと 検討してみても良いんじゃないかと。