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 は、Kotlin プログラムで大量の Java アノテーションプロセッサーをすぐに使用できるようにする優れたソリューションです。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 アノテーション処理 API との 100% の互換性。