Qtアプリケーションのバイナリサイズ縮小 – 第3部: 他のプラットフォーム

本稿は「Reducing Binary Size of Qt Applications – Part 3: More Platforms」の抄訳です。

macOS、iOS、Windows、Android、WebAssembly、Linux上向けの Qt ビルドの最適化

第1部 ではQtのサイズ最適化ガイドを紹介しました。 第2部では、Raspberry Pi(Linux)を使った具体的な例を取り上げました。

Linux は Qt がサポートする多くのプラットフォームのうちの1つですが、他のプラットフォームでサイズを最適化するにはどうすればよいのでしょうか?
一部の configure オプションはプラットフォーム依存であり、他のプラットフォームにそのまま適用できないこともあります。

このブログ記事では、Linux以外の各プラットフォームに注目します。主な目的は、それぞれのプラットフォームで使用できる参照用の機能セットを提供し、独自の構成を作る際の出発点として役立ててもらうことです。

リファレンス・アプリケーション

最小限の Qt 構成を作成する際には、どの機能を残すべきかを決める必要があります。
どの機能が必要かをよく理解していればいるほど、不要な機能を削減したり、許容できるパフォーマンスやセキュリティのトレードオフを判断しやすくなります。
この目的のために、私たちは最小構成で動作すべき Quick のサンプルアプリケーションをいくつか選定しました。

  • Coffeemachine - 前回のブログとの比較用 
  • Colorpalette Client - ネットワークと HTTPS を使用
  • Gallery - Qt Quick Controls を多数使用 
  • Calqlatr
  • Simple application -  QML の Window と Text 要素のみから成る、ミニマルな「Hello World」的参照アプリケーション 

プラットフォーム

これら6つのプラットフォーム上で構成の検証を行いました

コードベースには、最近の Qt 開発ブランチ(次期 Qt 6.10)を使用しました。
最小構成をコンパイルするために必要だった修正の多くは、Qt 6.9 や Qt 6.8 にもさかのぼって取り込まれています。

結果

最終的な構成は、CI(継続的インテグレーション)で使用している構成によって要約するのが最も適しています。各プラットフォーム間で構成オプションの多くは共通していますが、いくつか異なる点もあります。

特に注目すべきなのは、ほとんどのビルドがスタティックビルド(静的リンク)であることです。
スタティックビルドとは、アプリケーション本体、Qtライブラリ、Qtプラグインをすべて1つの実行ファイルにコンパイルする方式です。
この方法では、コンパイラやリンカがバイナリ全体を把握できるため、高度なサイズ最適化が可能になります。ただし、例外は Android です。現時点では Qt for Android はスタティックビルドをサポートしていません。

以下のグラフは、各アプリケーションのストレージサイズ(容量)を示しています。

  • Reference: デフォルト構成でビルドされたリリースアプリケーション
  • Reference stripped: シンボル情報を除去(ストリップ)したリファレンスアプリケーション
  • Minimal: 最小構成 でビルドされたアプリケーション
  • Minimal stripped: シンボル情報を除去した最小構成アプリケーション 

MacOS (Sequoia 15.2):

Picture

iOS (18.2):

Picture

Linux (Ubuntu 24.04): 

Picture

WebAssembly (emsdk 4.0.7):

Picture

注目すべき点として、WebAssembly の構成では LTO(Link Time Optimization)リンカフラグを直接使用しています。これは、Qt の -ltcg オプションを使うとコンパイラのバグに遭遇するためです。
このバグは最近修正されたため、将来的にはそのプラットフォームでも ltcg オプションを使用できるようになります。

Android (NDK 26.6.1):

Picture

Android ではビルドプロセスがデフォルトでバイナリをストリップするため、個別の「stripped(ストリップ済み)」ビルドは存在しません。

Windows (11, MSVC 2022):

Picture

Windows では、MSVC(Microsoft Visual C++)ではストリップ処理が使用されていない、あるいは必要とされていないようなので、個別のストリップ済みバージョンは存在しません(MinGW とは異なります)。

並べて比較する:

各プラットフォームごとのアプリケーションサイズを並べて見てみます。
まずは、最も大きなアプリケーションである Colorpalette Client からです。

Picture

次に、最も小さいアプリケーションである Simple application です。

Picture

すべてのプラットフォームで、サイズ最適化は大きな効果をもたらしています。おそらく予想通りですが、macOS と iOS のサイズはほぼ同じです。Android の APK が最も大きいサイズとなっています。
これは、静的ビルドがサポートされていないことや、androiddeployqt によるバンドルが必要以上のコンポーネントを含んでしまうことが原因と考えられます。幸いなことに、このバンドル内容は手動で調整可能です。詳しくはこのブログ記事をご参照ください。

さらなる最適化

最小構成は、選定したリファレンスアプリケーションが動作するように設計しています。
しかし、実際の製品アプリケーションにはそれぞれ特有の要件があり、さらに最適化することが可能です。以下はその例です:

  • アプリケーションでネットワーキング機能が不要なら無効化する(セキュリティ面でも有効)
  • QuickControls2 のスタイルをすべて使わないなら無効化し、ビルドもインポートもしない
  • 対応する画像フォーマットを減らす(たとえば、SVG対応はバイナリサイズにかなり影響が見られる)
  • 設定機能が不要なら無効化する(これもバイナリサイズの内訳に明確に現れる)

このほかにも多くの最適化ポイントがあります。
たとえばショートカット機能などはリファレンスアプリで使われているため最小構成に残っていますが、あなたのアプリでは不要かもしれません。

機能を無効化したら Qt がコンパイルできなくなった場合

ここで紹介した構成は、コンパイルを成功させるためにいくつかの小さなコード修正が必要でした。
これはある程度仕方のないことです。なぜなら、ありうるすべての機能の組み合わせを実際にコンパイルして確認するのは現実的ではないからです。(理論的には、機能の組み合わせは宇宙にある目に見える原子の数よりも多いと言われています。)

幸いなことに、必要な修正はたいてい非常に小さく簡単なものです。
もし標準外の機能セットを設定していて「動くはずのものが動かない」問題に遭遇したら、ぜひ Qt のバグトラッカーに報告するか、パッチを提出してください。

結論

機能の選択やビルドフラグは、Qt ライブラリやアプリケーションのサイズに大きな影響を与えます。
アプリケーションの必要要件をより正確に把握すればするほど、最適化の余地も大きくなります。
ここで紹介した最小構成は、独自のミニマイズされた構成を作るための良い出発点となるでしょう。

ただし、サイズを最小化したアプリケーションは開発時には必ずしも理想的ではない点に注意が必要です。開発時には必要なツールやシンボル情報を利用可能にしておくべきです。
さらに、リンク時コード生成(LTO)を使った静的ビルドは、共有ライブラリを使ったビルドよりもコンパイル時間が長くなります。


Blog Topics:

Comments