2013年12月19日

Qt + JSXあるいはJSの状況

JSXアドベントカレンダーのエントリーです。

2年ぐらい前から、QtをJavaScriptから使うというのをやっています。その延長でJSXから使うというのもずーっと、細く長くしぶとくチャレンジしています。12月12日に出たばかりのQt 5.2でうまくいきそうな感じなので、その成果を紹介します。コード片とかいっぱい書くのはめんどいので、コード片やサンプルはリンク先を参照してください。

Qt + JSの歴史

QtをJavaScriptから使うというのはかなり昔から先人たちによって行われてきたものの、今は誰も本気で取り組んでいなくて、ロストテクノロジーになりかけています。Qtは2007年5月リリースの4.3でQtScriptという名前でECMAScriptのエンジンを搭載しました。当初の目的はQtを使ったGUIプログラムのマクロ言語として使うというものでした。QtScriptEngineにQObjectを継承したオブジェクトを簡単に登録できるため、C++を使って作ったクラスを簡単にECMAScriptエンジンに公開することができます。簡単にECMAScriptの名前空間にメソッドや変数などを登録するAPIも持っています。当初はQt Script for Applicationsと呼ばれる処理系だったみたいですが、後にJavaScriptCoreが使われるようになりました。5.x系になって、V8が搭載されましたが、それはQMLとかQtQuickと呼ばれる環境向け限定で、スクリプティング用途では互換性のために相変わらずJavaScriptCoreが使われています。

当初はC++アプリケーションにスクリプティングを提供するのが目的でしたが、Qtのプログラム自体、全部JavaScriptで作ればいいんじゃね、ということで開始されたプロジェクトがQtScript Binding Genratorです。NokiaのQt Labsの公式です。ドキュメントとかほとんどないので経歴とかはよくわからないのですが、コミット日時をみると4.4のころにスタートしたみたいです。これはQtのクラスのうち、半分ぐらい(600/1200)のクラスのためのバインディングを提供します。コンストラクタ関数やら、可変長引数に対応したインスタンスメソッドやら、定数やら、protectedメソッドを予めオーバーライドしておいて、JSで定義されたメソッドにフォーワードするShell Classと呼ばれるクラス群を生成します。Qt Script Binding Generatorのソースコードを見ると、先行して開発されていたJava BindingのQt Jambiを流用して作らていることがわかります。4.6ぐらいまではNokiaがメンテしていましたが、その後メンテはとまっています。この間も、古いQt Labs、Google Code、新しいQt Labsといくつかリポジトリがありますが、Qt Labsが一応最後の公式リポジトリです。ちなみに最新の更新は2013年になっていますが、NokiaがQt事業をDigiaに譲渡だか売却した際の名義変更コミットだけで、更新はされてません。

その後は、Sarunas Valaskeviciusというイケメンイギリス人が5.0対応のコミットを大分前に行いました。5.0で内部のプライベートクラスの構造が色々変わったのですが、彼がそれへの対応をしました。ですが最終コミットが5.0正式リリース以前で、Generator(C++のヘッダをパースして、XMLを読み込んでコード生成する)は5.0対応になりましたが、言語間の差異を吸収するxmlファイルはほとんど変更されていませんでした。彼はその後、作ってV8を搭載したQML環境のためのBinding Generatorに注力しているため、5.0リリース前夜にpushされたコード以降メンテはされてません。。

僕はそのイケメンイギリス人のリポジトリをフォークして、ぼちぼちQt 5.0系の新しいモジュール構成に対応させたりしていました。5.1がリリースされたときに一度作りきったものの、生成したモジュールを動的にロードする部分が動かなくてあきらめていましたが、この前でた5.2ではめでたくうまく動いたのでようやく陽の目を見ることができそうな感じです。コード生成部を追加してJSXのJSラッパーコードも一緒に生成します。TypeScriptとかHaxeのラッパー作りたい人はどんどんフォークしてやっちゃってください。

Qt + JSの使い方

Binding Generatorで作ったQtScript用プラグインと、それをロードしてmain.jsというファイルを読み込んで起動するブートコードがQtWidget.jsという名前のプロジェクトです。ついでに、CommonJSスタイルのrequire、みんなだいすきconsole.logなんかも追加しています。あとはnode.js用コードとの互換性のために、process.argvだけ提供しています。本家のQt 5.2をインストールして、QtWidget.jsのリリースにあるバイナリ(Mac用とWindows用)をダウンロードして、main.jsを自分の好きなコードに置き換えて、macdeployqtとか、windeployqtという、Qtに付属のツールを使って必要なライブラリを集めたり動的ライブラリへのリンクを張り替えればOK、というのが基本の流れです。

トップページのスクリーンショットは、このバイナリを使って、Windows 8.1とMac OS Xの10.8で実行したものです。

Mac OSは複数バージョンのライブラリ、ヘッダファイルなどを集めたFrameworkというものでライブラリを提供しています。Qtも例外ではありません。アプリをリリースするときは、Qtを入れなくても動くように、必要なFrameworkを集めてきて、リンク先張替えを行って、バンドルしてリリースする必要があります。Windowsはもっとシンプルでライブラリとか必要なファイルを集めてくればOKです。今分かっている課題としては、WindowsでQtScriptプラグインの参照を読み込んで必要なライブラリを集める方法がわかっていません。あと、ライブラリファイルを集めるとかなりサイズがでかいです。100MBとかいっちゃうことも・・・

QtScriptからQtを利用する方法については、2012年12月に一人アドベントカレンダーのつもりで(途中で飽きたけど)集中的に書いたので、これを参照してもらえれば雰囲気は分かるかと思います。

自分でビルドしたい場合

今は気の利いたビルド環境は用意してなくて、シェルスクリプトとWindows用のバッチファイルぐらいです。QtWidget.jsをクローンして、Qt 5.2をインストールしてmakebinding.sh/batを叩けば、QtScriptのバインディングのプラグインができあがります。その後、QtWidget.jsのプロジェクトファイル(.pro)を、開いてビルドすればOKです。自前でビルドしたQtを使いたい場合はビルドスクリプトの中の変数を直接書き換えちゃってください。Windowsの方はmingw 4.8の32ビット環境で作っていますが、他のバイナリ用に作ることもできるでしょう。

まだ試してないですが、Qt 5.2はAndroidとiOSは正式対応していて、Qt 5.2のインストーラからインストールすることができます。また、Windows RT環境もバイナリは提供されていないもののビルドはできるようです。頑張ればこれらの環境でも動かせると思います。

JSXと一緒に使う

Qt + JSは仕事で一年以上コードを書いてきましたが、やはり型情報がないのはとても辛いです。こんなときのJSXです。JSXを信じるものは救われて幸せになれます。qt5.jsxというパッケージがnpmに登録されています。こちらがアナログ時計のサンプルコードを見れば雰囲気が分かってもらえると思います。

バインディングの問題としては、newしたいクラスや、変数の型として使いたいクラスはすべて明示的にimportしなければなりません。また、まだメソッドのパラメータの省略に関する情報を入れてないので、必ずnullとかデフォルトの値をいれなければなりません。あと、同名型違いのスロットは、型名が短い方のみが使えます。制約はあるものの、型によるコーディング補助があるお陰でかなりラクに書けます。

QtWidget.jsはprocess.argvが使えるようにしているので、JSXで--executable nodeを付けてビルドしてください。そんでもって、main.jsという名前で出力して、QtWidget.jsバイナリに含まれるJSファイルを置き換えればOKです。

本当はjsx-initのテンプレートとして作って、簡単にGUIプロジェクトを作れるようにすればいいかな、と思っているところですが、リリースされたばっかりでとりあえず動くようになったばかりなので、気長にお待ちください。

Qt 5.xの課題

Qtは5系になって、Firefox OSを除くほとんどのスマートフォン(iOS, Android, Windows Phoen/RT, Blackberry, Tizen, Ubuntu Touch)に対応するなど、イケイケドンドンに見えます。ですが、ちょっと使いづらいなぁ、と思う点もあります。

ひとつは、モジュール間の結合が密なことです。QtGuiが、QtGuiとQtWidgetsとQtPrintSupportとQtMultiMediaなどに別れたり、モジュールの規模が小さく、数を多くという方向で4系から5系でクラスの分類が再編されています。ですが、Guiをロードすると、画像フィルタプラグインとしてSVGをロードして、これがXMLモジュールをリンクして・・・など、結局ほとんどのモジュールが引っ張られる状態になっています。ファイルサイズもかなりでかい。ロジックをほとんどいれなくても100MBに達するようなこともあったり。

後は、おそらくLGPLのライセンス上の理由で、静的リンクができません。一応自前ビルドすればライブラリはコンパイルできますが、WebKitがリンクされません。Qtの商用ライセンスとの相性かな、と思います。静的リンクであれば、より厳密に必要なオブジェクトファイルだけをマージさせることができて、結果として小さなファイルになります。今は必要ファイルを一緒にバンドルして出荷する時代なので、共有ライブラリのメリットはかなり減っています。単独のアプリとして配る場合は無駄も多くなります。そんなこんなで、小さなツールをちょっと作るぐらいなら、node-webkitでいいかなぁ、と思っています(ミモフタモナイ)。

何はともあれ、JSXの用途がまたこれで広がったかなぁ、と思います。

posted by @shibukawa at 15:55 | TrackBack(0) | 日記 はてなブックマーク - Qt + JSXあるいはJSの状況
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/82811785
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック
検索ボックス

Twitter

www.flickr.com
This is a Flickr badge showing public photos and videos from shibukawa.yoshiki. Make your own badge here.
<< 2016年12月 >>
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
最近の記事
カテゴリ
過去ログ
Powered by さくらのブログ