KSPを使用する理由
コンパイラプラグインは、コード記述方法を大幅に強化できる強力なメタプログラミングツールです。コンパイラプラグインは、コンパイラをライブラリとして直接呼び出し、入力プログラムを解析および編集します。これらのプラグインは、さまざまな用途のために出力を生成することもできます。例えば、ボイラープレートコードを生成したり、Parcelable
のような特別なマークが付けられたプログラム要素の完全な実装を生成したりできます。プラグインには他にもさまざまな用途があり、言語に直接提供されていない機能を実装し、微調整するためにも使用できます。
コンパイラプラグインは強力ですが、そのパワーには代償が伴います。最もシンプルなプラグインを書くためにも、コンパイラに関するある程度のバックグラウンド知識と、特定のコンパイラの実装詳細に関するある程度の習熟度が必要です。もう1つの実用的な問題は、プラグインが特定のコンパイラバージョンに密接に結びついていることが多く、新しいバージョンのコンパイラをサポートするたびにプラグインを更新する必要があるかもしれないということです。
KSPは軽量なコンパイラプラグインの作成を容易にする
KSPはコンパイラの変更を隠蔽するように設計されており、それを使用するプロセッサのメンテナンス作業を最小限に抑えます。KSPはJVMに縛られないように設計されており、将来的に他のプラットフォームへより容易に適応できます。KSPはビルド時間を最小限に抑えるようにも設計されています。Glideなどの一部のプロセッサでは、KSPはkaptと比較して完全なコンパイル時間を最大25%削減します。
KSP自体もコンパイラプラグインとして実装されています。GoogleのMavenリポジトリには、プロジェクトを自分でビルドすることなくダウンロードして使用できるプリビルドパッケージがあります。
kotlincコンパイラプラグインとの比較
kotlinc
コンパイラプラグインはコンパイラのほぼすべてにアクセスできるため、最大のパワーと柔軟性を持っています。一方で、これらのプラグインはコンパイラのあらゆるものに依存する可能性があるため、コンパイラの変更に敏感であり、頻繁にメンテナンスする必要があります。これらのプラグインはまた、kotlinc
の実装に対する深い理解を必要とするため、学習曲線が急になる可能性があります。
KSPは、明確に定義されたAPIを通じてほとんどのコンパイラの変更を隠蔽することを目指していますが、コンパイラまたはKotlin言語自体の大きな変更は、APIユーザーに公開される必要がある場合があります。
KSPは、パワーと引き換えにシンプルさを提供するAPIにより、一般的なユースケースを満たそうとします。その機能は、一般的な kotlinc
プラグインの厳密なサブセットです。例えば、kotlinc
は式やステートメントを検査したり、コードを修正したりできますが、KSPはできません。
kotlinc
プラグインを書くのは非常に楽しいことですが、多くの時間がかかることもあります。kotlinc
の実装を学習する状況になく、ソースコードを修正したり式を読み取ったりする必要がない場合、KSPは良い選択肢となるかもしれません。
リフレクションとの比較
KSPのAPIは kotlin.reflect
に似ています。両者の主な違いは、KSPの型参照が明示的に解決される必要があることです。これがインターフェースが共有されていない理由の1つです。
kaptとの比較
kapt は、大量のJavaアノテーションプロセッサをKotlinプログラムでそのまま動作させる優れたソリューションです。kaptに対するKSPの主な利点は、ビルドパフォーマンスの向上、JVMに縛られないこと、よりKotlinらしいAPI、そしてKotlin固有のシンボルを理解できる能力です。
Javaアノテーションプロセッサを修正なしで実行するために、kaptはKotlinコードをJavaアノテーションプロセッサが関心を持つ情報を保持するJavaスタブにコンパイルします。これらのスタブを作成するために、kaptはKotlinプログラム内のすべてのシンボルを解決する必要があります。スタブ生成は、完全な kotlinc
解析の約1/3のコストがかかり、kotlinc
コード生成と同程度の時間がかかります。多くのアノテーションプロセッサにとって、これはプロセッサ自体が費やす時間よりもはるかに長いです。例えば、Glideは定義済みのアノテーションを持つごく限られた数のクラスを調べ、そのコード生成はかなり迅速です。ビルドオーバーヘッドのほとんどすべてがスタブ生成フェーズに存在します。KSPに切り替えることで、コンパイラに費やす時間を直ちに25%削減できます。
パフォーマンス評価のため、KSPでGlideの簡易版を実装し、Tachiyomiプロジェクトのコードを生成させました。テストデバイスでのプロジェクトのKotlin総コンパイル時間は21.55秒でしたが、kaptがコードを生成するのに8.67秒かかり、我々のKSP実装がコードを生成するのに1.15秒かかりました。
kaptとは異なり、KSPのプロセッサは入力プログラムをJavaの観点から見ません。APIはKotlinにより自然であり、特にトップレベル関数のようなKotlin固有の機能に優れています。KSPはkaptのように javac
に委譲しないため、JVM固有の振る舞いを前提とせず、他のプラットフォームでも潜在的に使用できます。
制限事項
KSPはほとんどの一般的なユースケースに対応するシンプルなソリューションを目指していますが、他のプラグインソリューションと比較していくつかのトレードオフを行っています。以下はKSPの目標ではありません:
- ソースコードの式レベルの情報を検査すること。
- ソースコードを修正すること。
- Java Annotation Processing APIとの100%の互換性。