なぜKSPなのか
コンパイラープラグインは、コードの記述方法を大幅に強化できる強力なメタプログラミングツールです。 コンパイラープラグインは、コンパイラーをライブラリとして直接呼び出し、入力プログラムを分析・編集します。これらのプラグインは、 さまざまな用途で出力を生成することもできます。例えば、ボイラープレートコードを生成したり、 Parcelable
のような特別なマークが付けられたプログラム要素の完全な実装を生成したりすることも可能です。プラグインには他にも様々な用途があり、 言語に直接提供されていない機能を実装したり、微調整したりするためにも使用できます。
コンパイラープラグインは強力ですが、その力には代償が伴います。最もシンプルなプラグインを作成するだけでも、 コンパイラーに関するある程度の予備知識と、使用する特定のコンパイラーの実装詳細に対するある程度の熟知が必要です。 もう一つの実用的な問題は、プラグインが特定のコンパイラーバージョンと密接に結びついていることが多い点です。 つまり、新しいバージョンのコンパイラーをサポートしたい場合、その度にプラグインを更新する必要があるかもしれません。
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における型参照が明示的に解決される必要がある点です。 これが、インターフェースが共有されていない理由の一つです。
kaptとの比較
kapt は、大量のJavaアノテーションプロセッサーをKotlinプログラムでそのまま動作させる、注目に値するソリューションです。 KSPがkaptに対して持つ主な利点は、ビルドパフォーマンスの向上、JVMに縛られないこと、よりKotlinらしいAPI、そしてKotlin専用のシンボルを理解する能力です。
Javaアノテーションプロセッサーを修正せずに実行するために、kaptはKotlinコードを、 Javaアノテーションプロセッサーが関心を持つ情報を保持するJavaスタブにコンパイルします。 これらのスタブを作成するには、kaptはKotlinプログラム内のすべてのシンボルを解決する必要があります。 スタブ生成は、完全な kotlinc
解析のおよそ1/3のコストと、kotlinc
コード生成と同程度のコストがかかります。 多くのJavaアノテーションプロセッサーにとって、これはプロセッサー自体が費やす時間よりもはるかに長いです。 例えば、Glideは定義済みのアノテーションを持つごく限られた数のクラスを調べ、そのコード生成はかなり迅速です。 ビルドオーバーヘッドのほとんどすべてがスタブ生成フェーズに存在します。 KSPに切り替えることで、コンパイラーが費やす時間を直ちに25%削減できます。
パフォーマンス評価のため、Tachiyomi プロジェクト用のコードを生成するために、 KSPでGlideの簡略版を実装しました。 テストデバイスでのプロジェクトのKotlin総コンパイル時間は21.55秒でしたが、 kaptがコードを生成するのに8.67秒かかり、我々のKSP実装がコードを生成するのには1.15秒しかかかりませんでした。
kaptとは異なり、KSPのプロセッサーは入力プログラムをJavaの視点からは見ません。 APIはKotlinにとってより自然であり、特にトップレベル関数のようなKotlin固有の機能に当てはまります。 KSPはkaptのように javac
に委譲しないため、JVM固有の動作を前提とせず、将来的には他のプラットフォームでも使用できる可能性があります。
制限事項
KSPはほとんどの一般的なユースケースに対するシンプルなソリューションを目指していますが、 他のプラグインソリューションと比較していくつかのトレードオフを行っています。 以下はKSPの目標ではありません。
- ソースコードの式レベルの情報を検査すること。
- ソースコードを修正すること。
- Javaアノテーション処理APIとの100%互換性。