Kotlin Compiler Pluginを作ってみる

Kenji Abe
6 min readMay 17, 2020

--

遊びでKotlin Compiler Pluginを作ってみました。色々と試行錯誤して分かったことをメモしておきます。

Compiler Pluginはbyte codeを編集することができます。ただし、Undocumentedなので自力で作るのはだいぶ大変です。

すでにあるものとして、All-open、android-extension などがあります。

細かい説明は Kotlin Conf 2018 のセッションを見ると良いと思います。

今回はこれらを見ながら自分で簡単なものを作ってみたので、どのように作るかをまとめておきます。

今回の例では、各メソッドの一番最初に println で実行するメソッド名を表示するようにしてみます。

サンプル

細かいコードは省略してるので、サンプルのほうも合わせて参照してください。

注意

繰り返しになりますが、 Undocumentedなので注意が必要です。この記事は試行錯誤して自分なり分かったことを書いていますので、その点注意してください。間違いなどあれば指定してもらえると嬉しいです。

Compiler Pluginの実装

まず CommandLineProcessorComponentRegistrar が必要になります。それに加えて実際の拡張処理を必要に応じて追加します。

CommandLineProcessor

CommandLineProcessor はCompiler Pluginの起点になるのと、オプションに関しての処理することになります。

ComponentRegistrar

次に ComponentRegistrar は実際の処理を行う拡張処理を登録します。この登録されたものが実行されて実際の処理を行うことになります。

ComponentRegistrar で使ってる、 ClassBuilderInterceptorExtension は後ほど説明します。

拡張処理

拡張処理はいくつかベースとなる処理があります。

今回はクラス作成の処理を拡張する ClassBuilderInterceptorExtension を使います。

他には、All-openでも使われてる、 アクセス修飾子に対して処理を行う DeclarationAttributeAltererExtension というのもあります。

このあたりうまく説明できない+完全に理解してるわけではないので、雰囲気で見てもらえると。。。

ClassBuilderInterceptorExtension はFactoryが必要なので、それを実装します。

次に実際にメソッドの処理を書き換えてみます。Compiler PluginはByte Codeを直接書く必要があります。

META-INF/services登録

CommandLineProcessorComponentRegistrar については
META-INF/services に登録します。

このあたりはサンプルのコードを見てもらえると。

Compiler Pluginを動かす

作ったCompilerをビルドしてjarファイルを作っておきます。

サンプルとして次のようなコードで試してみたいと思います。

Compiler Pluginなしで実行

最初は比較としてCompiler Pluginなしで実行すると次のような出力になります。

Hello World
test

コード上に書いた println のみが実行されてるのがわかります。

Compiler Pluignを使って実行

次にCompiler Pluginを使ってみます。色々やり方があるのですが、GradleのCompiler Optionを指定する方法でやってみます。

これで実行するとCompiler Pluginが出力を追加するようになります。

[Run `main` function]
Hello World
[Run `test` function]
test

(本当は kotlinc で試したかったんですけど、どうにもうまく行かなくてGradleを使いました)

Gradle Pluginを作る

Compiler Optionに指定するは面倒なので、Gradle Pluginを使って、簡単に使えるようにします。

Gradle Pluginの細かいところは省略しますが、基本は通常のGradle Pluginを作るのと同じです。

Compiler Pluginを使うためには、 KotlinGradleSubplugin というのを実装する必要があります。以下のような感じになります。

こちらも META-INF/services に登録が必要です。

あとは、これを作ったプラグインを使うようにするだけです。

Gradle Pluginがビルド時にCompiler PluginをDLしてきてて適用するような感じになります。

注意としては、Compiler PluginはGradleが解決できるRepositoryに配置する必要があります。サンプルではローカルのリポジトリを追加してあります。

参考

--

--

Kenji Abe
Kenji Abe

Written by Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO

No responses yet