From d89d6a365890735ec22ca6f1046bf85e53927107 Mon Sep 17 00:00:00 2001 From: Jonathan Gerrish Date: Mon, 6 Apr 2020 23:02:30 +0200 Subject: [PATCH] Adds a kt_plugin rule (#308) Creates a `kt_compiler_plugin` rule to allow kotlin compiler plugins to be specified, and then included with a `plugins=` attribute on kt_jvm_* jobs. This should support arbitrary kotlin compiler plugins, such as the android extensions, open-for-testing, and others. This does _not_ add an exported_plugins infrastructure (such as you get with java_plugins), and it does not change the special-case handling of kapt. It also doesn't do anything to resolve plugin inter-0compatibilities (e.g. the ABI plugin possibly needing information from the parcelizable, or other such interactions) The latter are issues yet to be figured out int he kotlinc plugin infrastructure, and we'll adapt this rule as appropriate. Also adds docs and examples. --- README.md | 35 ++++++++++++- examples/plugin/src/allopen/BUILD | 36 +++++++++++++ examples/plugin/src/allopen/OpenForTesting.kt | 3 ++ examples/plugin/src/allopen/User.kt | 9 ++++ examples/plugin/src/allopen/UserIsOpenTest.kt | 5 ++ examples/plugin/src/noarg/BUILD | 38 ++++++++++++++ examples/plugin/src/noarg/NoArgConstructor.kt | 3 ++ examples/plugin/src/noarg/User.kt | 9 ++++ .../src/noarg/UserHasNoargConstructorTest.kt | 13 +++++ examples/plugin/src/sam_with_receiver/BUILD | 31 +++++++++++ .../plugin/src/sam_with_receiver/Runner.java | 6 +++ .../src/sam_with_receiver/RunnerTest.kt | 5 ++ .../src/sam_with_receiver/SamWithReceiver.kt | 3 ++ kotlin/internal/compiler_plugins.bzl | 21 ++++++++ kotlin/internal/defs.bzl | 7 +++ kotlin/internal/jvm/compile.bzl | 29 +++++++++-- kotlin/internal/jvm/impl.bzl | 19 +++++++ kotlin/internal/jvm/jvm.bzl | 52 +++++++++++++++++++ kotlin/internal/jvm/plugins.bzl | 9 ++-- .../BUILD.com_github_jetbrains_kotlin | 15 ++++++ kotlin/kotlin.bzl | 2 + .../builder/KotlinBuilderComponent.java | 6 +-- .../kotlin/builder/tasks/KotlinBuilder.kt | 5 ++ .../tasks/jvm/KotlinJvmTaskExecutor.kt | 6 +-- .../builder/tasks/jvm/compilation_task.kt | 25 ++++++--- ...er.kt => KaptCompilerPluginArgsEncoder.kt} | 2 +- src/main/protobuf/kotlin_model.proto | 4 ++ 27 files changed, 376 insertions(+), 22 deletions(-) create mode 100644 examples/plugin/src/allopen/BUILD create mode 100644 examples/plugin/src/allopen/OpenForTesting.kt create mode 100644 examples/plugin/src/allopen/User.kt create mode 100644 examples/plugin/src/allopen/UserIsOpenTest.kt create mode 100644 examples/plugin/src/noarg/BUILD create mode 100644 examples/plugin/src/noarg/NoArgConstructor.kt create mode 100644 examples/plugin/src/noarg/User.kt create mode 100644 examples/plugin/src/noarg/UserHasNoargConstructorTest.kt create mode 100644 examples/plugin/src/sam_with_receiver/BUILD create mode 100644 examples/plugin/src/sam_with_receiver/Runner.java create mode 100644 examples/plugin/src/sam_with_receiver/RunnerTest.kt create mode 100644 examples/plugin/src/sam_with_receiver/SamWithReceiver.kt create mode 100644 kotlin/internal/compiler_plugins.bzl rename src/main/kotlin/io/bazel/kotlin/builder/toolchain/{KotlinCompilerPluginArgsEncoder.kt => KaptCompilerPluginArgsEncoder.kt} (98%) diff --git a/README.md b/README.md index 3b23dcc5f..c114caffa 100644 --- a/README.md +++ b/README.md @@ -161,9 +161,42 @@ kotlin_repositories() # if you want the default. Otherwise see custom kotlinc di kt_register_toolchains() # to use the default toolchain, otherwise see toolchains below ``` +# Kotlin compiler plugins + +The `kt_compiler_plugin` rule allows running Kotlin compiler plugins, such as no-arg, sam-with-receiver and allopen. + +For example, you can add allopen to your project like this: +```python +load("//kotlin:kotlin.bzl", "kt_compiler_plugin", "kt_jvm_library") + +kt_compiler_plugin( + name = "open_for_testing_plugin", + id = "org.jetbrains.kotlin.allopen", + options = { + "annotation": "plugin.allopen.OpenForTesting", + }, + deps = [ + "@com_github_jetbrains_kotlin//:allopen-compiler-plugin", + ], +) + +kt_jvm_library( + name = "user", + srcs = ["User.kt"], # The User class is annotated with OpenForTesting + plugins = [ + ":open_for_testing_plugin", + ], + deps = [ + ":open_for_testing", # This contains the annotation (plugin.allopen.OpenForTesting) + ], +) +``` + +Full examples of using compiler plugins can be found [here](examples/plugin). + ## Examples -Examples can be found in the [examples directory](https://github.com/bazelbuild/rules_kotlin/tree/master/examples), including usage with Android, Dagger, Node-JS, etc. +Examples can be found in the [examples directory](https://github.com/bazelbuild/rules_kotlin/tree/master/examples), including usage with Android, Dagger, Node-JS, Kotlin compiler plugins, etc. # History diff --git a/examples/plugin/src/allopen/BUILD b/examples/plugin/src/allopen/BUILD new file mode 100644 index 000000000..b33ada58f --- /dev/null +++ b/examples/plugin/src/allopen/BUILD @@ -0,0 +1,36 @@ +load("//kotlin:kotlin.bzl", "kt_compiler_plugin", "kt_jvm_library") + +kt_compiler_plugin( + name = "open_for_testing_plugin", + id = "org.jetbrains.kotlin.allopen", + options = { + "annotation": "plugin.allopen.OpenForTesting", + }, + deps = [ + "@com_github_jetbrains_kotlin//:allopen-compiler-plugin", + ], +) + +kt_jvm_library( + name = "open_for_testing", + srcs = ["OpenForTesting.kt"], +) + +kt_jvm_library( + name = "user", + srcs = ["User.kt"], + plugins = [ + ":open_for_testing_plugin", + ], + deps = [ + ":open_for_testing", + ], +) + +kt_jvm_library( + name = "user_is_open_test", + srcs = ["UserIsOpenTest.kt"], + deps = [ + ":user", + ], +) diff --git a/examples/plugin/src/allopen/OpenForTesting.kt b/examples/plugin/src/allopen/OpenForTesting.kt new file mode 100644 index 000000000..551688f67 --- /dev/null +++ b/examples/plugin/src/allopen/OpenForTesting.kt @@ -0,0 +1,3 @@ +package plugin.allopen + +annotation class OpenForTesting diff --git a/examples/plugin/src/allopen/User.kt b/examples/plugin/src/allopen/User.kt new file mode 100644 index 000000000..87cf6de32 --- /dev/null +++ b/examples/plugin/src/allopen/User.kt @@ -0,0 +1,9 @@ +package plugin.allopen; + +import java.util.* + +@OpenForTesting +data class User( + val userId: UUID, + val emails: String +) diff --git a/examples/plugin/src/allopen/UserIsOpenTest.kt b/examples/plugin/src/allopen/UserIsOpenTest.kt new file mode 100644 index 000000000..575b003fa --- /dev/null +++ b/examples/plugin/src/allopen/UserIsOpenTest.kt @@ -0,0 +1,5 @@ +package plugin.allopen + +import java.util.* + +class Subclass : User(UUID.randomUUID(), "test@example.org") diff --git a/examples/plugin/src/noarg/BUILD b/examples/plugin/src/noarg/BUILD new file mode 100644 index 000000000..5de0d4fc5 --- /dev/null +++ b/examples/plugin/src/noarg/BUILD @@ -0,0 +1,38 @@ +load("//kotlin:kotlin.bzl", "kt_compiler_plugin", "kt_jvm_library", "kt_jvm_test") + +kt_compiler_plugin( + name = "no_arg_plugin", + id = "org.jetbrains.kotlin.noarg", + options = { + "annotation": "plugin.noarg.NoArgConstructor", + }, + deps = [ + "@com_github_jetbrains_kotlin//:noarg-compiler-plugin", + ], +) + +kt_jvm_library( + name = "no_arg_constructor", + srcs = ["NoArgConstructor.kt"], +) + +kt_jvm_library( + name = "user", + srcs = ["User.kt"], + plugins = [":no_arg_plugin"], + deps = [ + ":no_arg_constructor", + ], +) + +# The no-arg constructor that is generated cannot be compiled against, but should be discoverable at runtime. +kt_jvm_test( + name = "user_has_noarg_constructor_test", + srcs = ["UserHasNoargConstructorTest.kt"], + test_class = "plugin.noarg.UserHasNoargConstructorTest", + deps = [ + ":user", + "@com_github_jetbrains_kotlin//:kotlin-reflect", + "@kotlin_rules_maven//:junit_junit", + ], +) diff --git a/examples/plugin/src/noarg/NoArgConstructor.kt b/examples/plugin/src/noarg/NoArgConstructor.kt new file mode 100644 index 000000000..8ab9276cc --- /dev/null +++ b/examples/plugin/src/noarg/NoArgConstructor.kt @@ -0,0 +1,3 @@ +package plugin.noarg + +annotation class NoArgConstructor diff --git a/examples/plugin/src/noarg/User.kt b/examples/plugin/src/noarg/User.kt new file mode 100644 index 000000000..19939da9f --- /dev/null +++ b/examples/plugin/src/noarg/User.kt @@ -0,0 +1,9 @@ +package plugin.noarg; + +import java.util.* + +@NoArgConstructor +data class User( + val userId: UUID, + val emails: String +) diff --git a/examples/plugin/src/noarg/UserHasNoargConstructorTest.kt b/examples/plugin/src/noarg/UserHasNoargConstructorTest.kt new file mode 100644 index 000000000..292cbb283 --- /dev/null +++ b/examples/plugin/src/noarg/UserHasNoargConstructorTest.kt @@ -0,0 +1,13 @@ +package plugin.noarg + +import org.junit.* +import java.lang.Exception + +class UserHasNoargConstructorTest { + @Test + fun userShouldHaveNoargConstructor() { + if (User::class.java.constructors.none { it.parameters.isEmpty() }) { + throw Exception("Expected an empty constructor to exist") + } + } +} diff --git a/examples/plugin/src/sam_with_receiver/BUILD b/examples/plugin/src/sam_with_receiver/BUILD new file mode 100644 index 000000000..03b90e60e --- /dev/null +++ b/examples/plugin/src/sam_with_receiver/BUILD @@ -0,0 +1,31 @@ +load("//kotlin:kotlin.bzl", "kt_compiler_plugin", "kt_jvm_library") +load("@rules_java//java:defs.bzl", "java_library") + +kt_compiler_plugin( + name = "sam_with_receiver_plugin", + id = "org.jetbrains.kotlin.samWithReceiver", + options = { + "annotation": "plugin.sam_with_receiver.SamWithReceiver", + }, + deps = [ + "@com_github_jetbrains_kotlin//:sam-with-receiver-compiler-plugin", + ], +) + +kt_jvm_library( + name = "sam_with_receiver", + srcs = ["SamWithReceiver.kt"], +) + +java_library( + name = "runner", + srcs = ["Runner.java"], + deps = [":sam_with_receiver"], +) + +kt_jvm_library( + name = "runner_test", + srcs = ["RunnerTest.kt"], + plugins = [":sam_with_receiver_plugin"], + deps = [":runner"], +) diff --git a/examples/plugin/src/sam_with_receiver/Runner.java b/examples/plugin/src/sam_with_receiver/Runner.java new file mode 100644 index 000000000..ce5f11e3f --- /dev/null +++ b/examples/plugin/src/sam_with_receiver/Runner.java @@ -0,0 +1,6 @@ +package plugin.sam_with_receiver; + +@SamWithReceiver +public interface Runner { + void run(Double shouldBecomeThis); +} diff --git a/examples/plugin/src/sam_with_receiver/RunnerTest.kt b/examples/plugin/src/sam_with_receiver/RunnerTest.kt new file mode 100644 index 000000000..122192aaf --- /dev/null +++ b/examples/plugin/src/sam_with_receiver/RunnerTest.kt @@ -0,0 +1,5 @@ +package plugin.sam_with_receiver + +val thisShouldWork = Runner { + println(this.isFinite()) +} diff --git a/examples/plugin/src/sam_with_receiver/SamWithReceiver.kt b/examples/plugin/src/sam_with_receiver/SamWithReceiver.kt new file mode 100644 index 000000000..907de9896 --- /dev/null +++ b/examples/plugin/src/sam_with_receiver/SamWithReceiver.kt @@ -0,0 +1,3 @@ +package plugin.sam_with_receiver + +annotation class SamWithReceiver diff --git a/kotlin/internal/compiler_plugins.bzl b/kotlin/internal/compiler_plugins.bzl new file mode 100644 index 000000000..4306a0d40 --- /dev/null +++ b/kotlin/internal/compiler_plugins.bzl @@ -0,0 +1,21 @@ +load( + "//kotlin/internal:defs.bzl", + _KtCompilerPluginInfo = "KtCompilerPluginInfo", +) + +def plugins_to_classpaths(providers_list): + flattened_files = [] + for providers in providers_list: + if _KtCompilerPluginInfo in providers: + provider = providers[_KtCompilerPluginInfo] + for e in provider.classpath: + flattened_files.append(e) + return flattened_files + +def plugins_to_options(providers_list): + kt_compiler_plugin_providers = [providers[_KtCompilerPluginInfo] for providers in providers_list if _KtCompilerPluginInfo in providers] + flattened_options = [] + for provider in kt_compiler_plugin_providers: + for option in provider.options: + flattened_options.append("%s:%s" % (option.id, option.value)) + return flattened_options diff --git a/kotlin/internal/defs.bzl b/kotlin/internal/defs.bzl index fddc2ce6f..2fe00b70d 100644 --- a/kotlin/internal/defs.bzl +++ b/kotlin/internal/defs.bzl @@ -35,3 +35,10 @@ KtJsInfo = provider( "srcjar": "The jar containing the sources of the library", }, ) + +KtCompilerPluginInfo = provider( + fields = { + "classpath": "The kotlin compiler plugin classpath", + "options": "List of plugin options, represented as structs with an id and a value field, to be passed to the compiler", + }, +) diff --git a/kotlin/internal/jvm/compile.bzl b/kotlin/internal/jvm/compile.bzl index 76c14f040..698369305 100644 --- a/kotlin/internal/jvm/compile.bzl +++ b/kotlin/internal/jvm/compile.bzl @@ -21,6 +21,11 @@ load( _merge_plugin_infos = "merge_plugin_infos", _plugin_mappers = "mappers", ) +load( + "//kotlin/internal:compiler_plugins.bzl", + _plugins_to_classpaths = "plugins_to_classpaths", + _plugins_to_options = "plugins_to_options", +) load( "//kotlin/internal/utils:utils.bzl", _utils = "utils", @@ -218,8 +223,10 @@ def kt_jvm_compile_action(ctx, rule_kind, output_jar): dirs = _compiler_directories(ctx) srcs = _partitioned_srcs(ctx.files.srcs) friend = _compiler_friends(ctx, friends = getattr(ctx.attr, "friends", [])) - compile_deps = _compiler_deps(toolchains, friend, deps = ctx.attr.deps) - plugins = _plugin_mappers.targets_to_kt_plugins(ctx.attr.plugins + ctx.attr.deps) + compile_deps = _compiler_deps(toolchains, friend, deps = ctx.attr.deps + ctx.attr.plugins) + annotation_processors = _plugin_mappers.targets_to_annotation_processors(ctx.attr.plugins + ctx.attr.deps) + plugins = ctx.attr.plugins + _run_kt_builder_action( ctx = ctx, rule_kind = rule_kind, @@ -228,6 +235,7 @@ def kt_jvm_compile_action(ctx, rule_kind, output_jar): srcs = srcs, friend = friend, compile_deps = compile_deps, + annotation_processors = annotation_processors, plugins = plugins, outputs = { "output": output_jar, @@ -263,7 +271,7 @@ def kt_jvm_compile_action(ctx, rule_kind, output_jar): ), ) -def _run_kt_builder_action(ctx, rule_kind, toolchains, dirs, srcs, friend, compile_deps, plugins, outputs): +def _run_kt_builder_action(ctx, rule_kind, toolchains, dirs, srcs, friend, compile_deps, annotation_processors, plugins, outputs): """Creates a KotlinBuilder action invocation.""" args = _utils.init_args(ctx, rule_kind, friend.module_name) @@ -279,17 +287,28 @@ def _run_kt_builder_action(ctx, rule_kind, toolchains, dirs, srcs, friend, compi # Collect and prepare plugin descriptor for the worker. args.add_all( "--processors", - plugins, + annotation_processors, map_each = _plugin_mappers.kt_plugin_to_processor, omit_if_empty = True, ) args.add_all( "--processorpath", - plugins, + annotation_processors, map_each = _plugin_mappers.kt_plugin_to_processorpath, omit_if_empty = True, ) + args.add_all( + "--pluginpath", + _plugins_to_classpaths(plugins), + omit_if_empty = True, + ) + args.add_all( + "--plugin_options", + _plugins_to_options(plugins), + omit_if_empty = True, + ) + progress_message = "Compiling Kotlin to JVM %s { kt: %d, java: %d, srcjars: %d }" % ( ctx.label, len(srcs.kt), diff --git a/kotlin/internal/jvm/impl.bzl b/kotlin/internal/jvm/impl.bzl index c188812c4..1a19d632f 100644 --- a/kotlin/internal/jvm/impl.bzl +++ b/kotlin/internal/jvm/impl.bzl @@ -17,6 +17,7 @@ load( ) load( "//kotlin/internal:defs.bzl", + _KtCompilerPluginInfo = "KtCompilerPluginInfo", _KtJvmInfo = "KtJvmInfo", ) load( @@ -192,6 +193,7 @@ def kt_jvm_junit_test_impl(ctx): main_class = ctx.attr.main_class, jvm_flags = ["-ea", "-Dbazel.test_suite=%s" % test_class] + ctx.attr.jvm_flags, ) + return _make_providers( ctx, providers, @@ -201,3 +203,20 @@ def kt_jvm_junit_test_impl(ctx): direct = ctx.files._java_runtime, ), ) + +def kt_compiler_plugin_impl(ctx): + merged_deps = java_common.merge([j[JavaInfo] for j in ctx.attr.deps]) + plugin_id = ctx.attr.id + options = [] + for (k, v) in ctx.attr.options.items(): + if "=" in k: + fail("kt_compiler_plugin options keys cannot contain the = symbol") + options.append(struct(id = plugin_id, value = "%s=%s" % (k, v))) + + return [ + merged_deps, + _KtCompilerPluginInfo( + classpath = merged_deps.transitive_runtime_jars.to_list(), + options = options, + ), + ] diff --git a/kotlin/internal/jvm/jvm.bzl b/kotlin/internal/jvm/jvm.bzl index ea95acf0c..e669051ba 100644 --- a/kotlin/internal/jvm/jvm.bzl +++ b/kotlin/internal/jvm/jvm.bzl @@ -93,6 +93,7 @@ kt_jvm_binary( load( "//kotlin/internal:defs.bzl", _KT_COMPILER_REPO = "KT_COMPILER_REPO", + _KtCompilerPluginInfo = "KtCompilerPluginInfo", _KtJvmInfo = "KtJvmInfo", _TOOLCHAIN_TYPE = "TOOLCHAIN_TYPE", ) @@ -102,6 +103,7 @@ load( ) load( "//kotlin/internal/jvm:impl.bzl", + _kt_compiler_plugin_impl = "kt_compiler_plugin_impl", _kt_jvm_binary_impl = "kt_jvm_binary_impl", _kt_jvm_import_impl = "kt_jvm_import_impl", _kt_jvm_junit_test_impl = "kt_jvm_junit_test_impl", @@ -184,6 +186,7 @@ _common_attr = utils.add_dicts( "plugins": attr.label_list( default = [], aspects = [_kt_jvm_plugin_aspect], + providers = [JavaInfo], ), "module_name": attr.string( doc = """The name of the module, if not provided the module name is derived from the label. --e.g., @@ -362,3 +365,52 @@ kt_jvm_import = rule( implementation = _kt_jvm_import_impl, provides = [JavaInfo, _KtJvmInfo], ) + +kt_compiler_plugin = rule( + doc = """Define a plugin for the Kotlin compiler to run. The plugin can then be referenced in the `plugins` attribute + of the `kt_jvm_*` rules. + + An example can be found under `//examples/plugin`: + + ```bzl + kt_compiler_plugin( + name = "open_for_testing_plugin", + id = "org.jetbrains.kotlin.allopen", + options = { + "annotation": "plugin.OpenForTesting", + }, + deps = [ + "@com_github_jetbrains_kotlin//:allopen-compiler-plugin", + ], + ) + + kt_jvm_library( + name = "open_for_testing", + srcs = ["OpenForTesting.kt"], + ) + + kt_jvm_library( + name = "user", + srcs = ["User.kt"], + plugins = [":open_for_testing_plugin"], + deps = [ + ":open_for_testing", + ], + ) + ``` + """, + attrs = { + "deps": attr.label_list( + doc = "The list of libraries to be added to the compiler's plugin classpath", + ), + "id": attr.string( + doc = """The ID of the plugin""", + ), + "options": attr.string_dict( + doc = """Dictionary of options to be passed to the plugin""", + default = {}, + ), + }, + implementation = _kt_compiler_plugin_impl, + provides = [JavaInfo, _KtCompilerPluginInfo], +) diff --git a/kotlin/internal/jvm/plugins.bzl b/kotlin/internal/jvm/plugins.bzl index beaa4fe67..99f883866 100644 --- a/kotlin/internal/jvm/plugins.bzl +++ b/kotlin/internal/jvm/plugins.bzl @@ -33,11 +33,14 @@ def _kt_plugin_to_processor(processor): def _kt_plugin_to_processorpath(processor): return [j.path for j in processor.classpath.to_list()] -def _targets_to_kt_plugins(targets): +def _targets_to_annotation_processors(targets): return depset(transitive = [t[KtJvmPluginInfo].annotation_processors for t in targets if t[KtJvmPluginInfo]]) +def _targets_to_plugins(targets): + return depset(transitive = [t[KtJvmPluginInfo].plugins for t in targets if t[KtJvmPluginInfo]]) + mappers = struct( - targets_to_kt_plugins = _targets_to_kt_plugins, + targets_to_annotation_processors = _targets_to_annotation_processors, kt_plugin_to_processor = _kt_plugin_to_processor, kt_plugin_to_processorpath = _kt_plugin_to_processorpath, ) @@ -47,7 +50,7 @@ def merge_plugin_infos(attrs): Returns: A KtJvmPluginInfo provider, Each of the entries is serializable.""" return KtJvmPluginInfo( - annotation_processors = _targets_to_kt_plugins(attrs), + annotation_processors = _targets_to_annotation_processors(attrs), ) def _kt_jvm_plugin_aspect_impl(target, ctx): diff --git a/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin index 31ca05885..b49368f18 100644 --- a/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin +++ b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin @@ -42,6 +42,21 @@ kt_jvm_import( ] ] +kt_jvm_import( + name = "allopen-compiler-plugin", + jar = "lib/allopen-compiler-plugin.jar", +) + +kt_jvm_import( + name = "noarg-compiler-plugin", + jar = "lib/noarg-compiler-plugin.jar", +) + +kt_jvm_import( + name = "sam-with-receiver-compiler-plugin", + jar = "lib/sam-with-receiver-compiler-plugin.jar", +) + # Kotlin dependencies that are internal to this repo and may be linked. [ java_import( diff --git a/kotlin/kotlin.bzl b/kotlin/kotlin.bzl index 344bf7652..db7cd0f89 100644 --- a/kotlin/kotlin.bzl +++ b/kotlin/kotlin.bzl @@ -23,6 +23,7 @@ load( ) load( "//kotlin/internal/jvm:jvm.bzl", + _kt_compiler_plugin = "kt_compiler_plugin", _kt_jvm_binary = "kt_jvm_binary", _kt_jvm_import = "kt_jvm_import", _kt_jvm_library = "kt_jvm_library", @@ -48,3 +49,4 @@ kt_jvm_import = _kt_jvm_import kt_jvm_library = _kt_jvm_library kt_jvm_test = _kt_jvm_test kt_android_library = _kt_android_library +kt_compiler_plugin = _kt_compiler_plugin diff --git a/src/main/kotlin/io/bazel/kotlin/builder/KotlinBuilderComponent.java b/src/main/kotlin/io/bazel/kotlin/builder/KotlinBuilderComponent.java index 5c0018ea4..a5752864e 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/KotlinBuilderComponent.java +++ b/src/main/kotlin/io/bazel/kotlin/builder/KotlinBuilderComponent.java @@ -23,7 +23,7 @@ import io.bazel.kotlin.builder.tasks.KotlinBuilder; import io.bazel.kotlin.builder.tasks.js.Kotlin2JsTaskExecutor; import io.bazel.kotlin.builder.tasks.jvm.KotlinJvmTaskExecutor; -import io.bazel.kotlin.builder.toolchain.KotlinCompilerPluginArgsEncoder; +import io.bazel.kotlin.builder.toolchain.KaptCompilerPluginArgsEncoder; import io.bazel.kotlin.builder.toolchain.KotlinToolchain; import javax.inject.Singleton; @@ -51,8 +51,8 @@ public interface Builder { @dagger.Module public class Module { @Provides - public KotlinCompilerPluginArgsEncoder providePluginArgEncoder(KotlinToolchain toolchain) { - return new KotlinCompilerPluginArgsEncoder( + public KaptCompilerPluginArgsEncoder providePluginArgEncoder(KotlinToolchain toolchain) { + return new KaptCompilerPluginArgsEncoder( toolchain.getKapt3Plugin().getJarPath(), toolchain.getKapt3Plugin().getId()); } diff --git a/src/main/kotlin/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt b/src/main/kotlin/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt index d2e8ba8a5..dd393b55f 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt @@ -76,6 +76,8 @@ class KotlinBuilder @Inject internal constructor( BOOT_CLASSPATH("--bootclasspath"), PROCESSOR_PATH("--processorpath"), PROCESSORS("--processors"), + PLUGIN_PATH("--pluginpath"), + PLUGIN_OPTION("--plugin_options"), EXT_CLASSPATH("--extclasspath"), EXT_DIR("--extdir"), OUTPUT("--output"), @@ -250,6 +252,9 @@ class KotlinBuilder @Inject internal constructor( addAllProcessors(argMap.optional(JavaBuilderFlags.PROCESSORS) ?: emptyList()) addAllProcessorpaths(argMap.optional(JavaBuilderFlags.PROCESSOR_PATH) ?: emptyList()) + addAllPluginpaths(argMap.optional(JavaBuilderFlags.PLUGIN_PATH) ?: emptyList()) + addAllPluginOptions(argMap.optional(JavaBuilderFlags.PLUGIN_OPTION) ?: emptyList()) + argMap.optional(JavaBuilderFlags.SOURCES)?.iterator()?.partitionJvmSources( { addKotlinSources(it) }, { addJavaSources(it) } diff --git a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt index 830ab0eca..6821f4af3 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt @@ -17,7 +17,7 @@ package io.bazel.kotlin.builder.tasks.jvm import io.bazel.kotlin.builder.toolchain.CompilationStatusException import io.bazel.kotlin.builder.toolchain.CompilationTaskContext -import io.bazel.kotlin.builder.toolchain.KotlinCompilerPluginArgsEncoder +import io.bazel.kotlin.builder.toolchain.KaptCompilerPluginArgsEncoder import io.bazel.kotlin.builder.toolchain.KotlinToolchain import io.bazel.kotlin.model.JvmCompilationTask import javax.inject.Inject @@ -32,14 +32,14 @@ const val X_FRIENDS_PATH_SEPARATOR = "," @Singleton class KotlinJvmTaskExecutor @Inject internal constructor( private val compiler: KotlinToolchain.KotlincInvoker, - private val pluginArgsEncoder: KotlinCompilerPluginArgsEncoder, + private val pluginArgsEncoderKapt: KaptCompilerPluginArgsEncoder, private val javaCompiler: JavaCompiler, private val jDepsGenerator: JDepsGenerator ) { fun execute(context: CompilationTaskContext, task: JvmCompilationTask) { val preprocessedTask = task .preProcessingSteps(context) - .runAnnotationProcessors(context, pluginArgsEncoder, compiler) + .runPlugins(context, pluginArgsEncoderKapt, compiler) context.execute("compile classes") { preprocessedTask.apply { diff --git a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/compilation_task.kt b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/compilation_task.kt index 957fc737b..4cceda0dd 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/compilation_task.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/compilation_task.kt @@ -19,7 +19,7 @@ package io.bazel.kotlin.builder.tasks.jvm import io.bazel.kotlin.builder.toolchain.CompilationTaskContext -import io.bazel.kotlin.builder.toolchain.KotlinCompilerPluginArgsEncoder +import io.bazel.kotlin.builder.toolchain.KaptCompilerPluginArgsEncoder import io.bazel.kotlin.builder.toolchain.KotlinToolchain import io.bazel.kotlin.builder.utils.IS_JVM_SOURCE_FILE import io.bazel.kotlin.builder.utils.bazelRuleKind @@ -52,6 +52,19 @@ internal fun JvmCompilationTask.baseArgs(): CompilationArgs = CompilationArgs() .flag("-jvm-target", info.toolchainInfo.jvm.jvmTarget) .flag("-module-name", info.moduleName) +internal fun pluginArgs(context: JvmCompilationTask, args: CompilationArgs): CompilationArgs = args + .let { + val pluginsPath = context.inputs.pluginpathsList.joinToString(":") + it.value("-Xplugin=${pluginsPath}") + } + .let { + var r = it + context.inputs.pluginOptionsList.forEach { opt -> + r = r.flag("-P", "plugin:$opt") + } + r + } + internal fun JvmCompilationTask.preProcessingSteps(context: CompilationTaskContext): JvmCompilationTask { return context.execute("expand sources") { expandWithSourceJarSources() } } @@ -79,17 +92,17 @@ internal fun JvmCompilationTask.produceSourceJar() { } } -internal fun JvmCompilationTask.runAnnotationProcessors( +internal fun JvmCompilationTask.runPlugins( context: CompilationTaskContext, - pluginArgsEncoder: KotlinCompilerPluginArgsEncoder, + kaptPluginArgsEncoder: KaptCompilerPluginArgsEncoder, compiler: KotlinToolchain.KotlincInvoker ): JvmCompilationTask { if (inputs.processorsList.isEmpty()) { return this } else { return context.execute("kapt (${inputs.processorsList.joinToString(", ")})") { - commonArgs() - .values(pluginArgsEncoder.encode(context, this)) + pluginArgs(this, commonArgs()) + .values(kaptPluginArgsEncoder.encode(context, this)) .values(inputs.kotlinSourcesList) .values(inputs.javaSourcesList).list().let { args -> context.executeCompilerTask( @@ -131,7 +144,7 @@ internal fun JvmCompilationTask.compileKotlin( compiler: KotlinToolchain.KotlincInvoker, printOnFail: Boolean = true ) = - commonArgs() + pluginArgs(this, commonArgs()) .values(inputs.javaSourcesList) .values(inputs.kotlinSourcesList) .list().let { args -> diff --git a/src/main/kotlin/io/bazel/kotlin/builder/toolchain/KotlinCompilerPluginArgsEncoder.kt b/src/main/kotlin/io/bazel/kotlin/builder/toolchain/KaptCompilerPluginArgsEncoder.kt similarity index 98% rename from src/main/kotlin/io/bazel/kotlin/builder/toolchain/KotlinCompilerPluginArgsEncoder.kt rename to src/main/kotlin/io/bazel/kotlin/builder/toolchain/KaptCompilerPluginArgsEncoder.kt index 770f07ac0..9024c145e 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/toolchain/KotlinCompilerPluginArgsEncoder.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/toolchain/KaptCompilerPluginArgsEncoder.kt @@ -21,7 +21,7 @@ import java.io.ObjectOutputStream import java.util.Base64 // TODO(hs) move the kapt specific stuff to the JVM package. -class KotlinCompilerPluginArgsEncoder( +class KaptCompilerPluginArgsEncoder( private val jarPath: String, private val pluginId: String ) { diff --git a/src/main/protobuf/kotlin_model.proto b/src/main/protobuf/kotlin_model.proto index 0615875ec..171ff1630 100644 --- a/src/main/protobuf/kotlin_model.proto +++ b/src/main/protobuf/kotlin_model.proto @@ -122,6 +122,10 @@ message JvmCompilationTask { repeated string processors = 7; // Annotation processor classpath. repeated string processorpaths = 8; + // Kotlin compiler plugin options + repeated string plugin_options = 9; + // Kotlin compiler plugin classpath + repeated string pluginpaths = 10; } CompilationTaskInfo info = 1;