はじめに
「Qt World Summit 2019 Berlin」( 以下QtWS)から2週間後の2019年11月19日~21日、同じベルリンで「Qt Contributors' Summit 2019」( 以下QtCS)が開催されました。
Qt Contributors' Summit 2019
URL:https://wiki.qt.io/Qt_Contributors_Summit_2019
QtCSはQtの開発者などのコントリビューターが集まり、今後のQt自体の開発の方向性などを議論する会議です。これまでは初夏に開催されることが多かったのですが、QtWSよりも後という珍しい時期の開催となりました。会場はThe Qt Company社のベルリンオフィスと、その隣にあるForum Adlashofでした。
初日はPlenary styleとしてForum Adlashofのみを使用して、多くの開発者達に影響がある内容を中心に、過去の議論を踏まえて決定された Qt 6 の方針などの認識の共有が主に行われました。2日目、3日目はThe Qt Company社の会議室も使用して、Unconference style で議論やワークショップが行われました。
メイン会場となったForum Adlershof
このレポートではQtCSの様子と、そこで議題となった内容を報告します。互いに関係するセッションも多かったため、各セッションを個別に報告するのではなく Qtのモジュール別にまとめての報告とさせていただきます。
なお、今年のQtCSには110名が参加登録をし、そのうち約3分の1がメンテナと呼ばれる各モジュールやコンポーネントの管理者で、約3分の1が承認者と呼ばれるコードレビューに承認する権限を持つ人たち、残りがコントリビューター(貢献者)とスポンサー、他のプロジェクトのコントリビューター等であったそうです。
Qt Contributors' Summit 2019のオープニング
Qt 6に向けて
まずはQt全体についてです。こちらは最初に行われたQt Projectのチーフメンテナであり、The Qt Company社のCTOでもあるLars Knoll氏のキーノート「Towards Qt 6」の内容がメインになります。同じタイトルのキーノートがQtともなじみの深いOSSプロジェクトKDEの開発者会議AkademyやQt World Summitでも実施されています。残念ながらそれらには参加できなかったのですが、Qtの内部実装をQt 5とQt 6で比較しての説明などがあり、おそらくQtCS向けに若干アレンジされたより深い内容になっていたのではないかと思います。
興味のある方は、Akademyでのビデオとスライド やQtWSでのビデオ などが公開されていますので確認してみてください。
Lars Knoll氏によるキーノート「Towards Qt 6」
今後のQtのロードマップですが、これまでの予定から大きな変化は無く、2019年末にQt 5.14、2020年初夏にQt 5系の最後のマイナーバージョンとなる5.15LTSをリリースし、今から約1年後の2020年末にQt 6をリリースする予定となっています。
Qt 6までに予定されているQt 5.14と5.15の位置付けについても説明がありました。「 Qt 5.14 and Qt 5.15LTS pave the road towards Qt 6」ということで、Qt 6へ向けた整備を行うためのリリースとなります。レガシーなAPIに非推奨(deprecatd)とマークしQt 6に不要なAPIを明示すること、またQt 6に追加する新機能についてテクニカルプレビューとして先行リリースを行い、そのフィードバックを受けることが主な目的となります。
Qt 6の正式リリース時には非推奨なAPIはすべて削除されます。そのため、Qt 6でのソースコード互換性は主にQt 5.15 LTSの(非推奨ではない)APIに対して確保する予定となっています。Qt 6へ向けた変更は多数に渡って行われる予定であるため、現行のQt 5.12LTSや5.13に対しては十分な互換性が確保されない可能性に注意してください。
Qt 6ではいくつかQt 5.15LTSとのソースコードが非互換となる変更も導入される予定です。「 Qt 6Changes / Migration」セッションではこれらのAPIに付いても議論されました。その中で従来はメジャーバージョン変更時に提供していたポーティング用補助ツールにQt 6ではClangベースのQt向け静的解析ツールであるClazyを活用する案も提案されました。C++部に限定はされますが、Clazyでソース非互換な変更に対応できれば、従来よりも正確かつ容易にメジャーバージョンアップ対応ができそうです。
Qt 6ではそのリリース形態に関しても変更が予定されています。Qt 5では各モジュールをEssentials,Add-onsに分類していましたが、それらのリリースは半年ごとにまとめて行っていました。しかし、Qtの機能・モジュールが増加するに従ってアーカイブ及びリリース作業の肥大化・複雑化を招いていました。たとえば、Qt 5.0.0のソースアーカイブはtar.xz形式で165MBほどですが、Qt 5.13.2では478MB、Qt 5.14.0では522MBと約3倍になっています。
Qt 6ではQt Core,GUI,Network,Widgets,QML,Quick+αの限られたモジュールをコアとして定義し、Essentialsモジュールのスリム化を図ります。Add-onsモジュールはサポート対象とサポート対象外に分割し、リリースをコアとは別に行うことでリリースの負荷を下げます。また、一部のモジュールはQt Marketplace経由でのリリースも考えているようです。
以下の方針もQt 6で行われる大きな変更点です。
特にCMakeは、これまで長らく使用していたqmakeを置き換えるものとしてQt全体へ影響します。すでに多くのモジュールがCMakeでビルドできるようになってはいますが、まだまだ課題も残っているそうです。Qt用に作られたqmakeに比べるとプロジェクトファイルの記法などは複雑になりますが、Qt自体をクロスコンパイルするときの手順の簡素化などが期待できるのではないかと思います。CMakeに関しては3日目には丸一日を使用したWorkshopも開催されていました。
C++17も大きな影響を与えます。といってもQtのAPI自体への影響はそれほど大きくなく、主にはQtの内部実装の効率化に寄与する見込みです。標準C++ライブラリの機能の利用は慎重に行います。パフォーマンスなどの評価を行った上でメリットがある場合はQt内部から使用したり、Qtの実装のバックエンドとして用いる予定です。そのため、Qtのビルドには比較的新しいコンパイラが必要となる予定です。たとえばMicrosoft Visual C++(MSVC)は2019以降が必要となる予定です。
このように、Qt 6では今後の10年間の利用に耐えられるだけのアプリケーションフレームワークとなることを目標としています。全体的にはQt 6ではスリム化とパフォーマンス改善が主な方針となって開発が進められています。これまでのQtの開発では、モジュールやAPIの削除時には代替手段の提供もセットとなることが多かったため規模が拡大する一方でした。Qt 6は初めてそのスリム化を行うリリースとなりそうです。
Qt Core
Qt Coreモジュールはその名の通りQtの核となるモジュールで、すべてのQtアプリケーション及びモジュールから利用されています。それだけに変更による影響が広範囲に及ぶため、互換性を確保するためにもこれまでは慎重に変更を行ってきました。しかし、Qt自体の肥大化にともないAPIも複雑性が増してきたこともあり、Qt 6では多数のAPIの整理が予定されています。
また、機能の整理だけではなく、Qt Coreの重要な機能であるプロパティシステムの刷新なども予定されています。
Qt 6のNew Property Systemでは、これまでQMLでJavaScript経由でのみ可能であったプロパティバインディングをC++で実現できるようになります。Qt 5までのプロパティはQ_PROPERTYマクロとゲッター・セッターメソッド、メタオブジェクトシステムを用いて提供されていました。Qt 6では新たにPropertyテンプレートクラスを導入し、これまでQMLエンジンで実現していたプロパティバインディングをC++のネイティブコードで動作可能に変更します。
この変更にともない、QObjectの派生クラスでなくてもプロパティを持てるようになり、バインディング式の計算をその評価時まで遅らせるレイジーバインディングも導入します。これらの変更により、簡単な式のバインディングでもQMLで実行した場合に比べて10倍以上のバインディング評価の高速化が達成できるということでした。
その他に変更を予定されている主なところでは
メタタイプシステム & QVariant
コンテナ
文字列(QString)
文字コード(コーデック)
などがあります。
メタタイプシステムはQVariantと実装を共通化し、これまで実行時に行っていた処理内容をコンパイル時に行うなどで、パフォーマンスに課題があったユーザ定義型の処理を改善します。
コンテナ系では使用するメリットの薄かったQListをQVectorのエイリアスへと変更し、統一します。その他、std::pairのように機能・パフォーマンス上問題の無い標準C++ライブラリの実装をQtのコンテナのバックエンドとして活用していきます。
文字列関連クラスも整理が行われます。たとえばQStringLiteralはQt 5で文字列リテラルの生成処理の高速化のために導入されたAPIですが、効率的な実装のためにはQStringやQLatin1Stringなどとの使い分けが必要で、バイナリサイズ増大などの副作用も存在していました。こういったパフォーマンス改善のための新規APIは、Qtの文字列関連APIを複雑にする原因ともなっていました。
これらを改善するため、QtのソースコードはUTF-8のみとしたうえで、不要な派生クラスは削除してユーザが無駄に悩む必要を無くします。
個人的に議論が長引いて驚いたのが文字コード(コーデック)関連です。QtではQt 2の頃から日本語などの文字コード変換用のクラス(QTextCodec)を独自に実装していました(コード自体は外部の人によるコントリビューションもあり、たとえば日本語系のコーデックは日本人が作成してコントリビュートしたものです) 。これらの独自実装はほとんどメンテナスされていないのに加えて、ICUなどの共通して利用可能なコーデック実装が存在しているため、現在では独自実装を維持する意義はほとんどありません。
また、Unicodeの普及にともなってWindows以外の環境ではUTF系のコーデックがあれば十分であり、Windowsでもローカルコーデックがあれば多くのケースに対応できることなどから、QTextCodec自体のQt Coreからの削除が提案されました。ただ、現状別ライブラリ化などの予定は無いため、Qt Coreから別モジュールへの移動なのか、Qt全体からの削除かなどが議題となりました。Qt全体からは一旦削除を行い、より適切なAPIと実装の提案があれば再導入もあり得るというのが現状のスタンスのようです。
ただ、その際にLars氏は別ライブラリ化を提案したのに対して、Qt CoreのメンテナであるThiago氏は
ICUなどの外部ライブラリを使用する場合にはQt自体のコードは小さいこと(日本語系や中国語系のコーデックは変換テーブルが大きいのが問題となっていました)
QTextStreamなど、Qt CoreにはQTextCodecを使いたいクラスがいくつかあること
などの点からQt Coreに戻せばいいのでは、という考えのようです。
この他、Windows以外のプラットフォームではLANG環境変数などで指定されたロケールに関係無くUTF-8をエンコーディングとして想定する動作に変更する予定に対して、他のエンコーディングを指定した場合にはどうするのかなどが議論されました。基本的にはUTF-8で動作するものの、ロケールでの指定と異なる場合は警告を出すという形で落ち着きそうです。
また、Clangの活用も議題となりました。Qtに含まれているツールであるmocやlupdateでは、その機能の実現のためにC++のパーサーが必要とされています。これまではQtの独自実装が使用されてきましたが、近年はC++の変化が激しく仕様への追従が課題となっていました。Qt Creatorでは独自実装からClangへの移行がほぼ終わりましたが、Qt本体ではmoc,lupdateが現在移行についての検討を行っています。
lupdateはQtの翻訳メッセージの抽出ツールです。正確にはQt CoreではなくQt Toolsに含まれているツールになります。ソースファイルに含まれる翻訳用メッセージを抽出するためにC++だけでなく、QMLなどのさまざまな言語用のパーサーが実装されています。
lupdateはClangを用いてメッセージを抽出するサンプル実装が既に動作可能な状態にあります。が、比較的簡易な構文解析で良い独自実装に対して、コンパイラそのものの一部であるClangでは抽象構文木(AST)の構築が非常に遅く、たとえばQt Creatorに対して翻訳を抽出した場合には従来の方式に比べて数倍の時間がかかっているそうです。これは多数のソースコードを処理する際に同じヘッダファイルを何度も解析していることも関係するようです。対策としてプリコンパイルドヘッダが利用できないか、あるいはジャンボビルドで対応できないかなどが議論されました。
なお、このlupdateのClang版ですが、これまでlupdateでは対応していなかったネストするnamespaceなどに対応できるメリットはあるものの、#ifでコンパイル対象外となる部分には対応できないなど一長一短となっています。このため当面は切り替えが可能な形で実装されるということでした。
mocはQtの根幹をなすメタタイプやメタオブジェト、シグナル・スロットを提供するために使用されています。こちらはC++専用ですが、クラスの宣言を読み込んで必要な実装を生成するためのマクロを検出するパーサーが実装されています。検出ミスがあっても比較的融通を利かせやすいlupdateに比べると、Qtを使用したプロジェクトでは必須な処理であるため、より厳密な動作が要求されるツールでもあります。ビルドにも実行にも大きく影響を与えるため、C++の新しい規格に対応が必要だという課題は共有されているものの、Clangを使用するというソリューションには慎重な意見も多数出ました。
これはClang自身やその依存ライブラリのサイズが大きいこと、ClangのAPIの変更に対して追従するコストが不明なこと、mocが必要なのはクラスの宣言だけでありソースコードのすべてを解析する必要は無くパフォーマンスが課題になる可能性があることなどもその原因です。
QtのQ_OBJECTマクロを使うmoc用マークをテンプレートやリフレクションを使ってmocを用いずに実現する方法はできないだろうか、という意見もありましたがソースコードの互換性を大きく破壊することなどもありQt 6では難しいと言うことでした。
このようにQt CoreはQt 6で大きく変化します。特に新しいプロパティシステムとC++によるプロパティバインディングはアプリケーションの実装に大きな影響を与えるかもしれません。
QML Version 3
QMLはQtが独自に作成した宣言型のUI記述言語です。QMLを利用したGUIであるQt Quickで使用されています。QMLはQt 6で最も大きな変化がある機能となります。ただ、他のモジュールではモジュール自体が変更されるのに対して、QMLではQt 4からQt 5への移行時と同じように新しいメジャーバージョンであるQML 3を追加する形での実装が行われる予定です。
このため、Qt 5のQt QuickアプリケーションはQML部分に関してはQML 2モジュールを用いることで、大きな変更を行わなくても移行できるのではないかと思われます。しかし、QML 2のままQt 6へ移行するのに比べると、QML 3への移行でパフォーマンスの大きな改善が狙えます。
QML 3ではQMLの位置付けが大きく変化します。これまでのQMLでは、HTML5+JavaScriptのようなスクリプト言語的な実行時のUI構築を、そのアーキテクチャの前提としていました。しかし、特に組み込み系でQMLファイルのロード時間を含めたアプリケーション起動時間が課題となるケースが多かったこと、JavaScriptエンジンが必要なためQt Widgetsモジュールが分離されたにもかかわらず、Qt Quickアプリケーションに必要なモジュールサイズが小さくならないこと、QMLアプリケーションの実装の品質にパフォーマンスが劇的に影響されることなどQML自体やその描画パフォーマンスへの評価は高いにもかかわらず、全体的なパフォーマンスに関しては課題が多いものとなっていました。
QMLファイルのロード時間などはQt 5でもQt Quick Compilerなどで対策をしてきましたが、メジャーバージョンアップのタイミングでアーキテクチャの見直しが入った形となります。
そのため、これまで実行時に行っていた初期化を可能な限りコンパイル時の処理に変更することや、JavaScriptではなくC++で実行することが全体的な方針となっています。
たとえば、従来のプロパティバインディングの式は基本的にJavaScriptエンジン上で動作し、簡易なものはキャッシュという形でJavaScriptをバイパスして動かしていました。また、JavaScriptもJITを使用するなどして高速化を図っていました。Qt 6ではQMLに記述された式をコンパイル時にネイティブなC++コードに変換させることでアプリケーションのサイズとパフォーマンスの双方の改善を行います。
Qt 5でもQt Quick Compilerという、アプリケーションビルド時にQMLをC++コードに変換する仕組みはありました。しかし、従来の仕組みでは中間コードへ変換しており、内部的にはJavaScriptエンジン経由で動いていました。Qt 6ではQML内のJavaScriptをC++へ変換することで、アプリケーションにはJavaScriptエンジンが必須ではなくなります。
上記に合わせて、Qt CoreのメタタイプやNew Property Systemなどの改善による相乗効果で、Qt全体のメモリ使用量とパフォーマンスの改善を図ります。
このあたりの技術(New Property Systemも含めて)はQt for MCUsに先行投入されています。Qt 6では、現状全く別のコードベースとなっているQtとQt for MCUsを統合して、MCU以外でも軽量なQtを動かすことができるようになることを目標としています。
この他にも、従来のQML 2で出た問題や複雑性の解決も議題となりました。たとえば以下のような項目です。
QMLモジュールのバージョン管理
グループプロパティ
コンテキストプロパティ
スコープ
モデルとビュー(デリゲート)の整合性
いずれもQMLの複雑性やツールのサポート(コード補完やデバッグなど)に影響を与えてきた機能です。たとえば、QMLモジュールのバージョン管理では、従来import文で必要であったバージョン指定の記述を廃止します。ほとんどの場合でバージョンを指定する意味はなかったため、納得のいく変更でしょう。
また、これに合わせてツール系の改善も行われます。たとえば、現状QMLのパースはQtとQt Creatorではそれぞれ別に実装されています(正確にはQtの実装をコピー・修正して使用しています) 。そこでQt QMLモジュールを実行時だけでなくツールからも利用可能な形へ作り直すことで、実装の重複やQt Creatorも含めたツール群の改善を図ります。特にQML language serverの早期構築を目指したいようです。QML language serverが実現すれば、Qt CreatorだけでなくVisual Studio Codeや他のIDEやエディタでQMLをより楽に扱うことができるようになるかもしれません。
このように全体的なアーキテクチャの変更が行われるQML 3ですが、言語の機能的には現状のQML 2のサブセット的な扱いにとどまる予定です。QMLの動的読み込み機能やJavaScriptエンジンは削除はされませんが、オプション機能となりアプリケーションからのリンクは必須ではなくなります。アプリケーションによってはQMLはコンパイル時にすべてC++コードへ変換され、QMLライブラリへのリンク自体が不要となることもあると想定されています。
QML3が追加されることで、Qt 6ではQML 2とQML 3が(しばらくの間は)併存する形となります。では、Qt QuickもQt Quick2とQt Quick 3で併存するのかが気になるところです。これについてはC++ライブラリとしてのQt Quickは、QML 2とQML 3の双方に対応するGUIライブラリとして1つのみ存在する形になるそうです。
Qt 5ではQt QuickモジュールがQt QMLモジュールに依存していますが、Qt QMLモジュールとは独立に動作可能な形へと変更するということでした。そのAPIがpublicなものになるかどうかなどはまだ不明ですが、以前から要望の多いC++経由でのQt Quick Scene Graphの利用がQt 6では可能になるかもしれません。
Qt 6 Graphics
グラフィック関連もQt 6で大きく変更される項目です。Qt 5ではOpenGLをすべてのプラットフォームでグラフィックAPIとして利用してきました。しかし、MetalやVulkanなどの新しいグラフィックAPIの登場によってOpenGL以外への対応も必要となってきました。Qt 5でもDirect3D12やVulkanへの対応を行おうとしましたが、OpenGLを前提としたアーキテクチャへの統合は困難であり、アプリケーション開発者も各APIへの個別対応が必要だったり、利用可能な機能が限定的であったりなどの課題があり中途半端なものとなっていました。
Qt 6ではその解決としてQt RHI(Rendering Hardware Interface)を導入します。Qt RHIはOpenGL,Metal,Vulkan,Direct3DなどのグラフィックAPIを統一的に扱うために新たに作成されたAPIです。Qt QuickなどのOpenGLを利用していた機能はQt RHIを用いて書き直され、OpenGLは必須ではなくなります。
すでにQt 5.14にはQt RHIをバックエンドに用いたQt Quick Scene Graphがテクニカルプレビューとして実装されています。5.14の段階ではすべてのプラットフォーム・APIへ対応はしていませんが、5.15で残りにも対応する予定です。これまでの実装状況からQt 6での大きなAPI変更は不要だろうとの見込みだそうです。ただし、当面はprivateなAPIとして提供され、アプリケーション開発者が直接使用することは想定されていません。
Qt 5でQt GUIモジュールに追加されたQOpenGL系クラスは、利用が非推奨となっていたQt OpenGLモジュールへ移動する予定です。
この他、私は参加できませんでしたがQt Widgetsの内部実装の改善についての議論や、QStyleクラスをQt QuickとQt Widgetsの双方で共有するための議論なども行われていました。QtWidgetsはQt Quickに比べると大きな変化は予定されていませんが、Qt 6でも継続的に細かな改良などが行われていきそうです。
Qt Project
この他に今年多かったのがQt Projectの運営に関するセッションです。Qtのリポジトリのブランチ管理方針から始まって、コントリビュータをさらに増やすための施策、コントリビューション体験を改善する方法などのさまざまなセッションが開かれました。
たとえば、現状バグ修正は最も古い安定かつサポート対象のブランチへコミットすることになっています。これはどのブランチで修正しやすいかどうかが比較的分かりやすいというメリットがありますが、新しいバージョンへのマージはQt Project側で行うため、マージまでのタイムラグが発生したりコンフリクト発生時の対応が大変な場合があるというデメリットもあります。この方針のままでいいのかなどの議論がありました。
また、Qtと関わりの深いKDEプロジェクトがこれまでどのようにして開発者を確保・維持してきたかの紹介などもありました。Google Code Summerの活用や、プロジェクトの活動状況の可視化、参加方法のドキュメント整備とメンテナンスなどによる参加ハードルの低下などを継続的に実施することで新規開発者の獲得と開発者のモチベーション低下を避けてきたと言うことでした。
QtはThe Qt Company社だけでも約140名が専属して開発に携わっています。他にもパートナーであるKDAB社をはじめとしてIntel社などの多数の企業や、KDEプロジェクトをはじめとするOSSプロジェクトなどがその開発・運営に関わっています。とはいえ、Qt自体の規模が大きいこともあり、十分な人数とは言えないのが現状です。先日発表のあったQt Marketplaceもそれに関連した施策の1つだと思われます。
QtCSではどうしてもコードに関連した議題がメインになりますが、Qt 6という大きな節目にを迎えるに当たって、コミュニティの拡大も目指したいということだと思います。
サブ会場となったThe Qt Company社のベルリンオフィス
まとめ
この他、Qt for Python関連も大きなトピックでした。Qtの開発者はC++がメインな人たちがまだまだ多いため、会場に集まった人たちの Qt for Pythonの利用率はあまり高くは無かったようですが、Qt for PythonのエンジニアであるCristián氏は、来年はその割合をもっと増やしたいと話していました。
3日間といういつもより長めの会期でしたが、どのセッションも話が尽きることはなく、非常に活発なサミットとなりました。これにはQtのメジャーバージョンアップにあたって拙速を避け、これまで十分に時間をかけてそのアーキテクチャなどの検討を続けてきたこともあると思います。影響の大きな機能については既にテクニカルプレビュー版が存在するものも多く、そのため概略やコンセプトだけでなく、具体的なコードや検討結果を基に議論が進められていきました。
Qt 6の正式リリース予定まで残り1年と十分な時間があるとは言えませんが、これまでの準備の成果か、大きな課題は残っていない印象です。2012年以来の8年ぶりとなるメジャーリリースは色々と面白いリリースとなりそうです。興味がある方はQt 5.14や5.15でいくつかの機能がテクノロジープレビュー版として試せるようになりますので、ぜひそちらもチェックしてみてください。
SRAのQt関連サービスご紹介
Qtの国内販売代理店として2003年からQtの普及・促進に貢献
Qtのライセンス販売だけでなく、コンサルティングから開発、サポートサービスまでをトータルに提供
多くのQtエンジニアが在籍しており、Qt開発受託の実績豊富
4名のQtコンサルタントにより、導入のご支援、パフォーマンスチューニング、Qt自身のカスタマイズ等のサービスを提供
Qtの導入を検討する顧客向けに、Qtプログラミング体験セミナーを無償で毎月開催
より実践的なプログラミングスキルを学べる有償トレーニングも毎月開催
詳細はSRAのQtサイト 参照