この記事は The Qt Blog の Qt in Visual Studio: A New Approach Based on MSBuild を翻訳したものです。
執筆: Miguel Costa, 2018年01月24日
前回の記事 でお知らせしたとおり、Qt Visual Studio ツールの新しいリリースにむけた作業をしています。このリリースに先駆けて、いくつかの大きな変更とその影響について紹介したいと思います。この記事では Qt のツールである moc、rcc、uic のビルド時やデザイン時のインテグレーションに関する新しいアプローチを紹介します。別の記事で、今回の変更がどのようにパフォーマンスの改善につながるのかを紹介したいと思います。
カスタムビルドツール
Visual Studio での外部の/サードパーティーのツールの統合は、これまで「カスタムビルド」という方法で実現してきました。ファイルに対して、例えば、Qt のマクロが含まれているヘッダファイルは moc による処理を行い、対応するメタオブジェクトのソースコードを生成するといった感じです。この場合、個々のヘッダファイルはカスタムビルドのアイテムとしてラベルづけがされ、そのカスタムビルドのためのプロパティページが存在しています。
このアプローチにはいくつかの欠点があります:
"In older versions of Visual C++, you can specify, for a specific file, a custom command that gets executed before the C++ compilation step. This functionality, called Custom Build Steps, has some limitations when working with large projects and complex external tools. You cannot set up a custom build command to be run on all files of a particular type. Also, just for using an external application as a custom build step, you need to have extended knowledge of the configuration flags available on the command line."
(Visual C++ の古いバージョンでは、特別なファイルに対して C++ のコンパイルのステップの前にカスタムコマンドを実行するように指定することができました。Custom Build Steps と呼ばれるこの機能は規模の大きなプロジェクトや複雑なツールを使用する際の制限事項が存在します。カスタムビルドコマンドを特定のタイプのすべてのファイルに対して行うような設定はできません。また、単に外部のアプリケーションを実行するためだけのために、コマンドラインで有効な設定用のフラグの知識を必要とします。)
https://msdn.microsoft.com/en-us/library/aa730877(v=vs.80).aspx
独自のプロパティページを持っているコンパイラやリンカのような Visual Studio に含まれるツールとは異なり、カスタムビルドのステップは一つのテキスト型の入力フィールドに外部ツールのパスと必要な引数を設定しなければいけないという制限があります。また、先ほど書いたとおり、カスタムビルドステップは「Qt のマクロが含まれるすべてのヘッダファイル」のようなファイルのグループに対して行うことができません。プロジェクトレベルで一つのグローバルなプロパティのセットを持つことは可能かもしれません。それぞれのファイルがそれぞれのカスタムビルドの情報を保持する必要があり、何度も作業を繰り返す必要があるにも関わらずプロジェクトファイルとは別のところにその設定が保存されます。これにより、Qt のような大規模のプロジェクトではカスタムビルドツールによる高負荷によりパフォーマンスが大幅に低減してしまいます。
MSBuild と Visual C++
新しい Visual Studio のバージョンでは MSBuild が Visual C++ のビルドエンジンとして採用されています。C++ のプロジェクトファイル(*.vcxproj)の内容は MSBuild XML スキーマ形式になっていて、ビルドプロセスは MSBuild のターゲットとタスクで管理されています。コンパイラやリンカのようなビルトインのツールは Visual Studio で「Rules」と呼ばれている定義に従って記述されており、特定のアイテムのタイプ(例えば C++ のソースファイル)に対するプロパティのセットが含まれています。このルール定義の文法も MSBuild XML スキーマに従っています。
外部ツールは、カスタムビルドステップを定義する代わりとして、特別な MSBuild のルールとターゲットを提供するだけで統合可能になります。カスタムビルドのメカニズムに事前に振る舞いを定義しておく方法と比べると、この新しいアプローチでは MSBuild の表現力を活かして外部ツールのコントロールをすることが可能になっています。また、外部ツールのためにルールを定義することにより、プロジェクトのファイルは汎用のカスタムビルドのアイテムとして扱われるのではなく、ツールへの入力として扱われます。コマンドラインを記述するための入力エリアが1つだけの状態ではなく、Visual Studio で指定の外部ツールでそれらのファイルを扱うためのプロパティページが用意されるでしょう。
Qt と MSBuild
Qt Visual Studio Tools の新しいバージョンは MSBuild のルールと moc や rcc、uic 向けのターゲット(Qt/MSBuild と呼ぶことにします)を提供します。これにより、ヘッダファイルを moc の入力にするようなことが可能になります。Visual Studio がこれらのファイル用に提供するプロパティページは moc 専用となり、そのツールが提供するすべてのオプションが指定可能になります。(rcc と uic も同様です。)Visual Studio のコンパイラなどの内部ツールと同様に、プロパティは特定のファイルに対してもプロジェクトレベルでグローバルにも設定が可能です。
新しいバージョンの Visual Studio Tools で作られたプロジェクトはカスタムビルドツールではなく Qt/MSBuild が利用されます。また、以前のプロジェクトのカスタムビルドツールをコンバートすることも可能です。新しいバージョンの VS Tools は以前のカスタムビルドツールも扱えるため、このコンバートは必須ではありません。.pro ファイルをインポートする際に、カスタムビルドツールから Qt/MSBuild のコンバートが自動で行われます。
Qt 特有のルールやターゲットが記述された XML ファイルは VS Tools のインストールパッケージに含まれていて、インストールした方は誰でも使えます。このファイルは VS Tools 自体に直接依存をしているわけではないため、Qt/MSBuild を利用したプロジェクトは、対応する XML ファイルをプロジェクトファイルと一緒に提供するだけで(VS Tools をインストールしていない人へも)共有が可能です。
MSBuild では、カスタムビルドツールではできなかったことが可能になっています。例えば、moc や rcc、uic の実行はカスタムビルドツールでは順番に行う選択肢しかありませんでしたが、これを並列化することが可能です。この機能は Qt/MSBuild では2つのターゲットで実装されています。最初のターゲットはすべての入力ファイルを走査し、個々のファイルに対するコマンドラインを生成し、作業の一覧に追加します。もう一つのターゲットでは、その一覧から作業を読み出し実際に実行します。これにより、期待通り、ビルドの時間が大幅に削減されます。
もうひとつの MSBuild のメリットは、どのプロジェクトファイルがどのツールで処理をされるかというレベルでビルドのプロセスに関与することができるということです。MSBuild のターゲットの内部では、ビルドアイテムの追加やそれに対する処理の選択が可能になっています。Qt/MBuild のターゲットでは Qt のクラスの定義がある C++ のソースファイルのハンドリングにこの機能を活用しています。対象のファイルは moc inputs というラベルのついたプロジェクトに手動で追加され、C++ コンパイラの入力として自動的にビルドプロセスに組み込まれます。
さらに、MSBuild の動的ソース機能を用いることで、ビルド時に、Qt のツールによって生成されたソースファイルが「オンザフライ」で C++ のコンパイルできるようになります。これにより、プロジェクト内に自動生成されたファイルをインクルードする必要がなくなりました。さらには VS Tools のパフォーマンスが改善されますが、これについては次のブログ記事のテーマとしましょう。
今後の改善予定
今回の moc や rcc、uic の新しいアプローチでは、Qt のツールと別のツールの両方にて処理がされるようなケースで問題が起こり得ます。カスタムビルドは複数のコマンドによる処理を可能とする一般的な仕組みなのでこういったユースケースも可能です。Qt のマクロが含まれているヘッダファイルを例にとると、moc だけがそういったファイルのカスタムビルドとして定義されることは保証できません。カスタムビルドから Qt/MSBuild へのコンバートでは、moc、rcc、uic のみが対象で、それ以外のカスタムビルドステップは無視されます。
このようなケースとして、IncrediBuild の統合があげられます。このツールがインストールされている場合、.pro ファイルを現在のバージョンの VS Tools でインポートすると、カスタムビルドステップには IncrediBuild が moc、rcc、uic を並行に(分散して)実行するための追加の設定が含まれるでしょう。今後のリリースでは、こういったケースはサポート外になる予定です。IncrediBuild を使用した Qt ツールの並列実行は可能ですが、ローカルマシンでのみの動作となるでしょう(ビルトインの C++ のコンパイラなどは分散実行可能です)。IncrediBuild については今後の VS Tools にて特別に対応する予定です。Qt のツールとその他のツールを組み合わせる場合の一般的なソリューションとしては、moc や rcc、uic のプロパティページでそのようなツールをプレ/ポストイベントとして扱うことを検討しています。
まとめ
この記事では、Visual Studio での moc、rcc、uic の新しいアプローチの概要を示しました。これにより Qt のツールも、ビルトインのツールと同等のアプローチで、デザイン時およびビルド時に動作することになります。次回の記事ではこれらの変更のパフォーマンス的なインパクトについて紹介する予定です。これらの改善がみなさんの Visual Studio 上での Qt アプリの開発の生産性の向上に寄与していることを願っています。