Skip to content

Commit

Permalink
Exmaple of using ksp without leveraging kapt architecture
Browse files Browse the repository at this point in the history
  • Loading branch information
restingbull committed Mar 8, 2024
1 parent 5d846b0 commit aab089c
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 23 deletions.
72 changes: 71 additions & 1 deletion examples/ksp/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ load("@rules_java//java:defs.bzl", "java_binary", "java_plugin")
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
load("@rules_kotlin//kotlin:core.bzl", "define_kt_toolchain", "kt_ksp_plugin")
load("@rules_kotlin//kotlin:core.bzl", "define_kt_toolchain", "kt_compiler_plugin", "kt_ksp_plugin", "kt_plugin_cfg")
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")

package(default_visibility = ["//visibility:public"])
Expand Down Expand Up @@ -81,3 +81,73 @@ build_test(
"//:coffee_app_deploy.jar",
],
)

kt_compiler_plugin(
name = "ksp",
compile_phase = True,
id = "com.google.devtools.ksp.symbol-processing",
options = {
"apclasspath": "{classpath}",
# projectBaseDir shouldn't matter because incremental is disabled
"projectBaseDir": "{temp}",
# Disable incremental mode
"incremental": "false",
# Directory where class files are written to. Files written to this directory are class
# files being written directly from the annotation processor, not Kotlinc
"classOutputDir": "{generatedClasses}",
# Directory where generated Java sources files are written to
"javaOutputDir": "{generatedSources}",
# Directory where generated Kotlin sources files are written to
"kotlinOutputDir": "{generatedSources}",
# Directory where META-INF data is written to. This might not be the most ideal place to
# write this. Maybe just directly to the classes directory?
"resourceOutputDir": "{generatedSources}",
# TODO(bencodes) Not sure what this directory is yet.
"kspOutputDir": "{temp}",
# Directory to write KSP caches. Shouldn't matter because incremental is disabled
"cachesDir": "{temp}",
# Include in compilation as an example. This should be processed in the stubs phase.
"withCompilation": "true",
# Set returnOkOnError to false because we want to fail the build if there are any errors
"returnOkOnError": "false",
"allWarningsAsErrors": "false",
},
deps = [
"@rules_kotlin//kotlin/compiler:symbol-processing-api",
"@rules_kotlin//kotlin/compiler:symbol-processing-cmdline",
],
)

kt_plugin_cfg(
name = "ksp_moshi",
options = {
},
plugin = ":ksp",
deps = [
"@maven//:com_squareup_moshi_moshi",
"@maven//:com_squareup_moshi_moshi_kotlin",
"@maven//:com_squareup_moshi_moshi_kotlin_codegen",
],
)

kt_jvm_library(
name = "raw_ksp_coffee_app_lib",
srcs = ["CoffeeAppModel.kt"],
plugins = [
"//:ksp",
"//:ksp_moshi",
],
deps = [
"@maven//:com_google_auto_service_auto_service_annotations",
"@maven//:com_google_auto_value_auto_value_annotations",
"@maven//:com_squareup_moshi_moshi",
"@maven//:com_squareup_moshi_moshi_kotlin",
],
)

build_test(
name = "raw_ksp_lib_test",
targets = [
"//:raw_ksp_coffee_app_lib",
],
)
6 changes: 6 additions & 0 deletions examples/ksp/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
###############################################################################
# Bazel now uses Bzlmod by default to manage external dependencies.
# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel.
#
# For more details, please check https://github.com/bazelbuild/bazel/issues/18958
###############################################################################
32 changes: 17 additions & 15 deletions kotlin/internal/jvm/impl.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -385,40 +385,39 @@ def _deshade_embedded_kotlinc_jars(target, ctx, jars, deps):
],
)

def _resolve_plugin_options(id, string_dict):
def _resolve_plugin_options(id, string_list_dict, expand_location):
"""
Resolves plugin options from a string dict to a dict of strings.
Args:
id: the plugin id
string_dict: a dict of strings
string_list_dict: a dict of list[string].
Returns:
a dict of strings
"""
options = []
for (k, v) in string_dict.items():
if "=" in k:
fail("kt_compiler_plugin options keys cannot contain the = symbol")
options.append(KtCompilerPluginOption(id = id, value = k + "=" + v))
for (k, vs) in string_list_dict.items():
for v in vs:
if "=" in k:
fail("kotlin compiler option keys cannot contain the = symbol")
value = k + "=" + expand_location(v) if v else k
options.append(KtCompilerPluginOption(id = id, value = value))
return options

# This is naive reference implementation for resolving configurations.
# A more complicated plugin will need to provide its own implementation.
def _resolve_plugin_cfg(info, options, deps):
classpath = []
for dep in deps:
if JavaInfo in dep:
classpath.append(dep[JavaInfo].compile_jars)
def _resolve_plugin_cfg(info, options, deps, expand_location):
ji = java_common.merge([dep[JavaInfo] for dep in deps if JavaInfo in dep])
classpath = depset(ji.runtime_output_jars, transitive = [ji.transitive_runtime_jars])
return KtPluginConfiguration(
id = info.id,
options = _resolve_plugin_options(info.id, options),
classpath = depset(transitive = classpath),
options = _resolve_plugin_options(info.id, options, expand_location),
classpath = classpath,
data = depset(),
)

def kt_compiler_plugin_impl(ctx):
plugin_id = ctx.attr.id
options = _resolve_plugin_options(plugin_id, ctx.attr.options)

deps = ctx.attr.deps
info = None
Expand All @@ -437,6 +436,9 @@ def kt_compiler_plugin_impl(ctx):

classpath = depset(info.runtime_output_jars, transitive = [info.transitive_runtime_jars])

# TODO(1035): Migrate kt_compiler_plugin.options to string_list_dict
options = _resolve_plugin_options(plugin_id, {k: [v] for (k, v) in ctx.attr.options.items()}, ctx.expand_location)

return [
DefaultInfo(files = classpath),
_KtCompilerPluginInfo(
Expand All @@ -451,7 +453,7 @@ def kt_compiler_plugin_impl(ctx):

def kt_plugin_cfg_impl(ctx):
plugin = ctx.attr.plugin[_KtCompilerPluginInfo]
return plugin.resolve_cfg(plugin, ctx.attr.options, ctx.attr.deps)
return plugin.resolve_cfg(plugin, ctx.attr.options, ctx.attr.deps, ctx.expand_location)

def kt_ksp_plugin_impl(ctx):
info = java_common.merge([dep[JavaInfo] for dep in ctx.attr.deps])
Expand Down
5 changes: 3 additions & 2 deletions kotlin/internal/jvm/jvm.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -622,9 +622,10 @@ kt_plugin_cfg = rule(
"plugin": attr.label(
doc = "The plugin to associate with this configuration",
providers = [_KtCompilerPluginInfo],
mandatory = True,
),
"options": attr.string_dict(
doc = "A list of plugin configuration options.",
"options": attr.string_list_dict(
doc = "A dictionary of flag to values to be used as plugin configuration options.",
),
"deps": attr.label_list(
doc = "Dependencies for this configuration.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,15 @@ internal fun JvmCompilationTask.plugins(
xFlag("plugin", it)
}

val dirTokens = mapOf(
val optionTokens = mapOf(
"{generatedClasses}" to directories.generatedClasses,
"{stubs}" to directories.stubs,
"{temp}" to directories.temp,
"{generatedSources}" to directories.generatedSources,
"{classpath}" to classpath.joinToString(File.pathSeparator)
)
options.forEach { opt ->
val formatted = dirTokens.entries.fold(opt) { formatting, (token, value) ->
val formatted = optionTokens.entries.fold(opt) { formatting, (token, value) ->
formatting.replace(token, value)
}
flag("-P", "plugin:$formatted")
Expand Down
3 changes: 2 additions & 1 deletion src/main/starlark/core/plugin/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ KtCompilerPluginInfo = provider(
"stubs": "Run this plugin during kapt stub generation.",
"compile": "Run this plugin during koltinc compilation.",
"options": "List of plugin options, represented as KtCompilerPluginOption, to be passed to the compiler",
"resolve_cfg": """"A Callable[[KtCompilerPluginInfo, Dict[str,str], List[Target], KtPluginConfiguration] that resolves an associated plugin configuration.""",
"resolve_cfg": "A Callable[[KtCompilerPluginInfo, Dict[str,str], List[Target], KtPluginConfiguration]" +
" that resolves an associated plugin configuration.",
},
)

Expand Down
2 changes: 0 additions & 2 deletions src/main/starlark/core/repositories/setup.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ def kt_configure():

native.register_toolchains("@released_rules_kotlin//kotlin/internal:default_toolchain")

native.register_toolchains("@released_rules_kotlin//kotlin/internal:default_toolchain")

maven_install(
name = "kotlin_rules_maven",
fetch_sources = True,
Expand Down

0 comments on commit aab089c

Please sign in to comment.