このブログは「What's new in QML Tooling in 6.11, part 1: QML Language Server (qmlls)」を翻訳したものです。
最新のQtリリースであるQt 6.11が、まもなく公開されます。この短いブログ記事シリーズでは、Qt 6.11でQMLツール群がもたらす新機能をご紹介します。第1部となる今回は、qmllsから始めます。第2部(こちら)および第3部(こちら)では、前回のQMLツール群に関するブログ記事以降に追加されたqmllintの警告と、QMLツール群におけるコンテキストプロパティ設定のサポートについて解説します。
Qt 6.11に同梱されているqmllsは、Qt 6.10以降を対象とするプロジェクトにおいて、C++の定義へのジャンプ機能をサポートしています。この機能を使用するには、Qt Creator用のこのガイドまたはVS Code用のこのガイドに従って、お使いのエディタでqmllsを有効にしてください。スクリーンショットではQt Creatorを使用します。
たとえば、C++で定義されたQML要素を含むプロジェクトがあるとします:
qmllsがC++の定義を見つけるためには、MyItemを定義するファイルが、QMLモジュールのCMakeLists.txt内のqt_add_qml_module呼び出しに含まれている必要があります:
エディタで、MyItemを使用しているQMLファイルを開き、MyItemを右クリックして、Qt Creatorではカーソル下のシンボルを追跡を、VS Codeでは定義へ移動を選択してください。あるいは、MyItemをCtrlキーを押しながらクリック(macOSの場合はCmdキーを押しながらクリック)することもできます。
qmlls を使用すると、エディタが MyItem を定義している C++ ファイルを開き、MyItem が定義されている行にカーソルを移動させるはずです。
C++で定義されたQMLコンポーネントのプロパティ、メソッド、およびその他のメンバーについても、同様に機能するはずです。
Qt 6.11のリリース前に、この新機能を試してみたい場合は、スタンドアロンのqmllsリリースをご利用いただけます。Qt CreatorとVS Codeの両方に、スタンドアロンのqmllsバージョンをダウンロードするオプションが用意されています。詳細は、Qt Creatorはこちら、VS Codeはこちらをご覧ください。
6.11以前のバージョンでは、qmllsの単一インスタンスでは、複数のQMLプロジェクトを同時に扱うことができませんでした。インポートパスやビルドパスなどのプロジェクト固有の情報は、以前はグローバルなものであり、開いているすべてのプロジェクト間で共有されていました。このため、誤ったインポートパスや無関係なインポートパスの使用が原因で、リンティング中に誤ったインポート警告が表示されるなどの不具合が発生することがありました。
バージョン6.11では、前述のバグが発生することなく、エディタからqmllsで複数のプロジェクトを開ける機能を追加しました。これにより、Visual Studioなど、qmllsのインスタンスを複数起動できないエディタに対するサポートが強化されました。
qmllsが同一インスタンス内で複数のプロジェクトを正しく開くためには、エディターは開く各プロジェクトのルートプロジェクトフォルダを宣言し、各プロジェクトのビルドパス情報を渡す必要があります。
エディタは、Language Server Protocolのワークスペースフォルダ機能を使用して、qmllsなどの言語サーバーに「プロジェクトのルートフォルダ」を通知することができます。各プロジェクトのルートフォルダには、インポートパスを含む独自の設定があり、QMLファイルはファイルパスを通じてそれぞれのプロジェクトのルートフォルダにマッピングされます。
たとえば、ワークスペースフォルダが3つある場合:
すると、qmllsは次のファイルを開きます
同じ qmlls インスタンスで複数のプロジェクトを開く場合、ビルドパスの情報を渡すのは少し難しくなります。コマンドライン引数や環境変数を通じて渡された情報は、すべてのワークスペースフォルダに適用されてしまうためです。そのため、qmlls クライアントは、各プロジェクトのビルドパスを個別に指定する必要があります。
ビルドパス情報を渡すために、エディタは、ワークスペースフォルダからビルドパスへのマッピングを含むAddBuildDirsParamsパラメータを伴う$/addBuildDirs通知を送信することができます。
export interface UriToBuildDir {
baseUri: URI;
buildDirs: string[];
}
export interface AddBuildDirsParams {
buildDirsToSet: UriToBuildDir[];
}
この情報をもとに、qmllsは各ワークスペースフォルダに対応するビルドフォルダからプロジェクト固有の情報を読み込みますが、ワークスペース間で型定義やインポートパスを混同することはありません。
次のような状況を想像してみてください。C++で定義されたMyComponentというQMLコンポーネントがあり、これをQMLファイルで使用しているのですが、MyComponentを変更したいとします。qmllsは、プロジェクトのビルドが完了するまで、MyComponentへの変更を認識できません。例えば、MyComponentに最近追加されたプロパティは認識されません。この状況では、MyComponentを変更するたびに、QMLでの使用箇所を適用したり修正したりする前に、プロジェクトをビルドし直さなければなりません。これにより、次のような反復的なループに陥る可能性があります:
ステップ2は忘れられがちであり、開発プロセスに手間をかける原因となります。ステップ2を忘れた場合、ステップ3で「新しく追加されたプロパティが存在しない」といった古い警告が表示される可能性があります。CMake Calls機能を使用すれば、ステップ2はqmllsによって自動的に実行されます。
qmllsは、起動時およびC++ヘッダーファイルの変更時にCMakeを呼び出します。qmllsは、ビルドフォルダ内の型情報を使用して、C++コンポーネントを定義するヘッダーファイルを特定し、監視します。C++ヘッダーファイルが変更されたり、ディスクに保存されたりすると、ファイル監視機能がqmllsに通知します。
このCMake呼び出しにより、all_qmltyperegistrationというCMakeターゲットがビルドされ、qmllsに必要な型情報が生成されます。このターゲットは、プロジェクトのQMLに関係のない部分のビルドを回避するよう設計されているため、プロジェクト全体のビルドよりも負荷が軽くなっています。リソースの過剰な消費を防ぐため、qmllsではデフォルトでCMake呼び出しに1つのジョブを使用します。カスタマイズ方法については、こちらをご覧ください。
Qt 6.12では、エディタが対応している場合、CMakeの呼び出しが開始されると、qmllsがエディタ内に進行状況インジケータを表示するようにする予定です。Qt Creator および VS Code では、すでに進行状況インジケーター機能がサポートされています。エディタ内から、進行状況バーの (x) ボタンをクリックすることで、バックグラウンドでのビルドをキャンセルすることができます。qmlls は、ビルドが完了すると進行状況バーを閉じ、ビルドフォルダから情報を再読み込みして、最新の qmllint 警告や定義への移動先などを生成します。
この機能は、Qt Creator ではデフォルトで無効になっていますが、VS Code やその他のエディタではデフォルトで有効になっているはずです。
この機能を有効または無効にするには、
Qt 6.11におけるqmllsの新機能、すなわち「C++定義への移動」、複数プロジェクトのサポート、およびCMake呼び出し機能についてご紹介しました。また、Qt 6.12で導入予定のCMake呼び出しの進行状況インジケーターについても、少しだけお見せしました。
何かおかしな点や、期待通りに動作しないことがありましたら、https://qt-project.atlassian.net/jira/for-you にて、お気軽にバグ報告をご登録ください。