Kotlin 编译器架构剖析
周末在家正刷着 GitHub 呢,微信收到一条消息:“森哥,像 ksp , allopen 这些 Kotlin 的编译器插件,它们是怎么 run 起来的,看了半天一头雾水”,我心想,不应该呀,十有八九是通过 SPI 来实现插件的加载的“,于是,我赶紧瞅了一眼 JetBrains/Kotlin 的代码,找到了 KotlinGradleSubplugin.kt,于是,假装很懂的样子,发了一个 KotlinGradleSubplugin.kt 的代码截图给他。
“这个我看过了,我想知道 all-open 这个插件究竟是在什么时候修改类的修饰符的”
呃。。。,看来,是编不下去了,只好 clone 了 JetBrains/Kotlin 的代码下来开始仔细研究。
PluginCliParser
经过一番连蒙带猜,在 PluginCliParsers.kt 中发现了这段代码:
1 | object PluginCliParser { |
果然不出所料,是通过 SPI 来加载插件的,只不过没有直接用 ServiceLoader ,而是用的 ServiceLoaderLite.kt,来看看它跟 JDK 提供的 ServiceLoader 有什么不一样。
ServiceLoaderLite
代码注释写得很清楚,原来是因为 JDK 8 的 bug — ServiceLoader 文件句柄泄露 🤣
1 | /** |
从实现来看,ServiceLoaderLite.kt 是直接从 URLClassLoader 的 classpath 来遍历所有的 JAR 文件中的 SPI 配置文件。
Kotlin Compiler 架构
整个 Kotlin 编译器分为 front-end 和 back-end ,back-end 主要工作是生成平台相关的代码,平台无关的工作基本上都是由 front-end 来完成,其结构如下图所示:
Kotlin 的编译器有三种启动方式:
- Kotlin Gradle Plugin
- JPS (Jetbrains Project System) — JetBrains 基于 Gant 开发的一款构建框架,主要用在 JetBrains 的 IDEA 全家桶中
- kotlinc 命令
Kotlin Gradle Plugin
平常我们使用 Kotlin 基本上都是在 Gradle 环境中使用,而 Kotlin 的 Gradle 插件启动流程如下图所示:
Kotlin Compiler Plugin
Kotlin 编译器本身提供了一些扩展接口,允许开发者基于 Kotlin 编译器开发一些插件,像官方提供的插件有:
除此之外,还有 Google 推出的 KSP (Kotlin Symbol Processing API),Kotlin 编译器提供的扩展接口有:
-
主要是给 Kotlin Gradle 插件用,因为 Compiler 插件是不依赖于 Gradle 的,所以,需要由 Gradle 插件将 Compiler 插件加载进来,
KotlinGradleSubplugin
就是用来配置 Compiler 对应的依赖,以及一些 Compiler 要用到的编译选项。 -
主要是向 Compiler 注册一些 Compiler Extension (不是 Android Gradle Plugin 的那种 Extension),Compiler Extension 既有 front-end 的,也有 back-end 的。
Front-End 的 Extension 有:
- AnnotationBasedExtension
- CollectAdditionalSourcesExtension
- CompilerConfigurationExtension
- DeclarationAttributeAltererExtension
- PreprocessedVirtualFileFactoryExtension
- …
Back-End 的 Extension 有:
-
主要是用来处理通过命令行传递给插件的参数,格式为:
-P plugin:<plugin-id>:<key>=<value>
。
kotlinc
kotlinc 的大致的启动过程如下图所示,由于过程太过复杂,省略了一些细节,以便于帮忙大家更快的理解 kotlinc 是如何工作的:
结语
了解了 Kotlin 编译器的整体架构,我们就可以基于 Kotlin 编译器来开发自己的插件了,而且,Kotlin 从语法上就具备了语言间的互操作性,加上 Kotlin 编译器的可扩展能力,这给了我们无限的想像空间。
- 本文链接:https://johnsonlee.io/2020/09/26/kotlin-compiler-architecture-inside/
- 版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。