383 lines
18 KiB
Python
383 lines
18 KiB
Python
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
#
|
|
# This source code is licensed under both the MIT license found in the
|
|
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
|
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
|
# of this source tree.
|
|
|
|
load("@prelude//android:android_providers.bzl", "merge_android_packageable_info")
|
|
load(
|
|
"@prelude//java:java_library.bzl",
|
|
"build_java_library",
|
|
"split_on_archives_and_plain_files",
|
|
)
|
|
load(
|
|
"@prelude//java:java_providers.bzl",
|
|
"JavaLibraryInfo",
|
|
"JavaPackagingDepTSet",
|
|
"JavaPackagingInfo",
|
|
"JavaProviders",
|
|
"create_java_library_providers",
|
|
"create_native_providers",
|
|
"derive_compiling_deps",
|
|
"to_list",
|
|
)
|
|
load(
|
|
"@prelude//java:java_toolchain.bzl",
|
|
"AbiGenerationMode",
|
|
"JavaToolchainInfo",
|
|
)
|
|
load("@prelude//java/plugins:java_annotation_processor.bzl", "create_ap_params", "create_ksp_ap_params")
|
|
load("@prelude//java/plugins:java_plugin.bzl", "create_plugin_params")
|
|
load("@prelude//java/utils:java_utils.bzl", "get_abi_generation_mode", "get_default_info", "get_java_version_attributes", "get_path_separator")
|
|
load(
|
|
"@prelude//kotlin:kotlin_toolchain.bzl",
|
|
"KotlinToolchainInfo",
|
|
)
|
|
load("@prelude//kotlin:kotlincd_jar_creator.bzl", "create_jar_artifact_kotlincd")
|
|
load("@prelude//utils:utils.bzl", "map_idx")
|
|
|
|
_JAVA_OR_KOTLIN_FILE_EXTENSION = [".java", ".kt"]
|
|
|
|
def _create_kotlin_sources(
|
|
ctx: "context",
|
|
srcs: ["artifact"],
|
|
deps: ["dependency"],
|
|
annotation_processor_params: [["AnnotationProcessorParams"], None],
|
|
ksp_annotation_processor_params: ["AnnotationProcessorParams", None],
|
|
additional_classpath_entries: ["artifact"]) -> ("artifact", ["artifact", None], ["artifact", None]):
|
|
"""
|
|
Runs kotlinc on the provided kotlin sources.
|
|
"""
|
|
|
|
kotlin_toolchain = ctx.attrs._kotlin_toolchain[KotlinToolchainInfo]
|
|
compile_kotlin_tool = kotlin_toolchain.compile_kotlin[RunInfo]
|
|
kotlinc = kotlin_toolchain.kotlinc[RunInfo]
|
|
kotlinc_output = ctx.actions.declare_output("kotlinc_classes_output")
|
|
|
|
compile_kotlin_cmd = cmd_args([
|
|
compile_kotlin_tool,
|
|
"--kotlinc_output",
|
|
kotlinc_output.as_output(),
|
|
])
|
|
java_toolchain = ctx.attrs._java_toolchain[JavaToolchainInfo]
|
|
zip_scrubber_args = ["--zip_scrubber", cmd_args(java_toolchain.zip_scrubber, delimiter = " ")]
|
|
compile_kotlin_cmd.add(zip_scrubber_args)
|
|
|
|
kotlinc_cmd_args = cmd_args([kotlinc])
|
|
|
|
compiling_classpath = [] + additional_classpath_entries
|
|
compiling_deps_tset = derive_compiling_deps(ctx.actions, None, deps + kotlin_toolchain.kotlinc_classpath)
|
|
if compiling_deps_tset:
|
|
compiling_classpath.extend(
|
|
[compiling_dep.abi for compiling_dep in list(compiling_deps_tset.traverse())],
|
|
)
|
|
|
|
classpath_args = cmd_args(
|
|
compiling_classpath,
|
|
delimiter = get_path_separator(),
|
|
)
|
|
|
|
# write joined classpath string into args file
|
|
classpath_args_file, _ = ctx.actions.write(
|
|
"kotlinc_classpath",
|
|
classpath_args,
|
|
allow_args = True,
|
|
)
|
|
|
|
compile_kotlin_cmd.hidden([compiling_classpath])
|
|
|
|
kotlinc_cmd_args.add(["-classpath"])
|
|
kotlinc_cmd_args.add(cmd_args(classpath_args_file, format = "@{}"))
|
|
|
|
module_name = ctx.label.package.replace("/", ".") + "." + ctx.label.name
|
|
kotlinc_cmd_args.add(
|
|
[
|
|
"-module-name",
|
|
module_name,
|
|
"-no-stdlib",
|
|
"-no-reflect",
|
|
] + ctx.attrs.extra_kotlinc_arguments,
|
|
)
|
|
|
|
jvm_target = _get_kotlinc_compatible_target(ctx.attrs.target) if ctx.attrs.target else None
|
|
if jvm_target:
|
|
kotlinc_cmd_args.add([
|
|
"-jvm-target",
|
|
jvm_target,
|
|
])
|
|
|
|
kapt_generated_sources_output = None
|
|
if annotation_processor_params:
|
|
compile_kotlin_cmd.add(["--kapt_annotation_processing_jar", kotlin_toolchain.annotation_processing_jar[JavaLibraryInfo].library_output.full_library])
|
|
compile_kotlin_cmd.add(["--kapt_annotation_processors", ",".join([p for ap in annotation_processor_params for p in ap.processors])])
|
|
compile_kotlin_cmd.add(["--kapt_annotation_processor_params", ";".join([p for ap in annotation_processor_params for p in ap.params])])
|
|
|
|
annotation_processor_classpath_tsets = (
|
|
filter(None, ([ap.deps for ap in annotation_processor_params])) +
|
|
[dep[JavaPackagingInfo].packaging_deps for dep in [kotlin_toolchain.annotation_processing_jar, kotlin_toolchain.kotlin_stdlib]]
|
|
)
|
|
annotation_processor_classpath = ctx.actions.tset(
|
|
JavaPackagingDepTSet,
|
|
children = annotation_processor_classpath_tsets,
|
|
).project_as_args("full_jar_args")
|
|
kapt_classpath_file = ctx.actions.write("kapt_classpath_file", annotation_processor_classpath)
|
|
compile_kotlin_cmd.add(["--kapt_classpath_file", kapt_classpath_file])
|
|
compile_kotlin_cmd.hidden(annotation_processor_classpath)
|
|
|
|
sources_output = ctx.actions.declare_output("kapt_sources_output")
|
|
compile_kotlin_cmd.add(["--kapt_sources_output", sources_output.as_output()])
|
|
classes_output = ctx.actions.declare_output("kapt_classes_output")
|
|
compile_kotlin_cmd.add(["--kapt_classes_output", classes_output.as_output()])
|
|
stubs = ctx.actions.declare_output("kapt_stubs")
|
|
compile_kotlin_cmd.add(["--kapt_stubs", stubs.as_output()])
|
|
|
|
kapt_generated_sources_output = ctx.actions.declare_output("kapt_generated_sources_output.src.zip")
|
|
compile_kotlin_cmd.add(["--kapt_generated_sources_output", kapt_generated_sources_output.as_output()])
|
|
compile_kotlin_cmd.add(["--kapt_base64_encoder", cmd_args(kotlin_toolchain.kapt_base64_encoder[RunInfo], delimiter = " ")])
|
|
generated_kotlin_output = ctx.actions.declare_output("kapt_generated_kotlin_output")
|
|
compile_kotlin_cmd.add(["--kapt_generated_kotlin_output", generated_kotlin_output.as_output()])
|
|
if jvm_target:
|
|
compile_kotlin_cmd.add(["--kapt_jvm_target", jvm_target])
|
|
|
|
friend_paths = ctx.attrs.friend_paths
|
|
if friend_paths:
|
|
concat_friends_paths = cmd_args([friend_path.library_output.abi for friend_path in map_idx(JavaLibraryInfo, friend_paths)], delimiter = ",")
|
|
kotlinc_cmd_args.add(cmd_args(["-Xfriend-paths", concat_friends_paths], delimiter = "="))
|
|
|
|
zipped_sources, plain_sources = split_on_archives_and_plain_files(srcs, _JAVA_OR_KOTLIN_FILE_EXTENSION)
|
|
|
|
kotlinc_cmd_args.add(plain_sources)
|
|
|
|
ksp_zipped_sources_output = None
|
|
if ksp_annotation_processor_params:
|
|
ksp_cmd = cmd_args(compile_kotlin_tool)
|
|
ksp_cmd.add(zip_scrubber_args)
|
|
|
|
if ksp_annotation_processor_params.deps:
|
|
ksp_cmd.add(["--ksp_processor_jars"])
|
|
ksp_cmd.add(cmd_args(ksp_annotation_processor_params.deps.project_as_args("full_jar_args"), delimiter = ","))
|
|
|
|
ksp_cmd.add(["--ksp_classpath", classpath_args])
|
|
ksp_classes_and_resources_output = ctx.actions.declare_output("ksp_output_dir/ksp_classes_and_resources_output")
|
|
ksp_cmd.add(["--ksp_classes_and_resources_output", ksp_classes_and_resources_output.as_output()])
|
|
ksp_output = cmd_args(ksp_classes_and_resources_output.as_output()).parent()
|
|
ksp_cmd.add(["--ksp_output", ksp_output])
|
|
ksp_sources_output = ctx.actions.declare_output("ksp_output_dir/ksp_sources_output")
|
|
ksp_cmd.add(["--ksp_sources_output", ksp_sources_output.as_output()])
|
|
ksp_zipped_sources_output = ctx.actions.declare_output("ksp_output_dir/ksp_zipped_sources_output.src.zip")
|
|
ksp_cmd.add(["--ksp_zipped_sources_output", ksp_zipped_sources_output.as_output()])
|
|
ksp_cmd.add(["--ksp_project_base_dir", ctx.label.path])
|
|
|
|
ksp_kotlinc_cmd_args = cmd_args(kotlinc_cmd_args)
|
|
_add_plugins(ctx, ksp_kotlinc_cmd_args, ksp_cmd, is_ksp = True)
|
|
|
|
ksp_cmd_args_file, _ = ctx.actions.write(
|
|
"ksp_kotlinc_cmd",
|
|
ksp_kotlinc_cmd_args,
|
|
allow_args = True,
|
|
)
|
|
|
|
ksp_cmd.add("--kotlinc_cmd_file")
|
|
ksp_cmd.add(ksp_cmd_args_file)
|
|
ksp_cmd.hidden(ksp_kotlinc_cmd_args)
|
|
|
|
ctx.actions.run(ksp_cmd, category = "ksp_kotlinc")
|
|
|
|
zipped_sources = (zipped_sources or []) + [ksp_zipped_sources_output]
|
|
compile_kotlin_cmd.add(["--ksp_generated_classes_and_resources", ksp_classes_and_resources_output])
|
|
|
|
_add_plugins(ctx, kotlinc_cmd_args, compile_kotlin_cmd, is_ksp = False)
|
|
|
|
if zipped_sources:
|
|
zipped_sources_file = ctx.actions.write("kotlinc_zipped_source_args", zipped_sources)
|
|
compile_kotlin_cmd.add(["--zipped_sources_file", zipped_sources_file])
|
|
compile_kotlin_cmd.hidden(zipped_sources)
|
|
|
|
args_file, _ = ctx.actions.write(
|
|
"kotlinc_cmd",
|
|
kotlinc_cmd_args,
|
|
allow_args = True,
|
|
)
|
|
|
|
compile_kotlin_cmd.hidden([plain_sources])
|
|
|
|
compile_kotlin_cmd.add("--kotlinc_cmd_file")
|
|
compile_kotlin_cmd.add(args_file)
|
|
compile_kotlin_cmd.hidden(kotlinc_cmd_args)
|
|
|
|
ctx.actions.run(compile_kotlin_cmd, category = "kotlinc")
|
|
|
|
return kotlinc_output, kapt_generated_sources_output, ksp_zipped_sources_output
|
|
|
|
def _is_ksp_plugin(plugin: str.type) -> bool.type:
|
|
return "symbol-processing" in plugin
|
|
|
|
def _add_plugins(
|
|
ctx: "context",
|
|
kotlinc_cmd_args: "cmd_args",
|
|
compile_kotlin_cmd: "cmd_args",
|
|
is_ksp: bool.type):
|
|
for plugin, plugin_options in ctx.attrs.kotlin_compiler_plugins.items():
|
|
if _is_ksp_plugin(str(plugin)) != is_ksp:
|
|
continue
|
|
|
|
kotlinc_cmd_args.add(cmd_args(["-Xplugin", plugin], delimiter = "="))
|
|
options = []
|
|
for option_key, option_val in plugin_options.items():
|
|
# "_codegen_dir_" means buck should provide a dir
|
|
if option_val == "__codegen_dir__":
|
|
option_val = ctx.actions.declare_output("kotlin_compiler_plugin_dir")
|
|
options.append(cmd_args([option_key, option_val.as_output()], delimiter = "="))
|
|
compile_kotlin_cmd.add(["--kotlin_compiler_plugin_dir", option_val.as_output()])
|
|
else:
|
|
options.append(cmd_args([option_key, option_val], delimiter = "="))
|
|
|
|
if options:
|
|
kotlinc_cmd_args.add(["-P", cmd_args(options, delimiter = ",")])
|
|
|
|
# kotlinc is strict about the target that you can pass, e.g.
|
|
# error: unknown JVM target version: 8. Supported versions: 1.6, 1.8, 9, 10, 11, 12
|
|
def _get_kotlinc_compatible_target(target: str.type) -> str.type:
|
|
return "1.6" if target == "6" else "1.8" if target == "8" else target
|
|
|
|
def kotlin_library_impl(ctx: "context") -> ["provider"]:
|
|
packaging_deps = ctx.attrs.deps + ctx.attrs.exported_deps + ctx.attrs.runtime_deps
|
|
if ctx.attrs._build_only_native_code:
|
|
shared_library_info, cxx_resource_info = create_native_providers(ctx.actions, ctx.label, packaging_deps)
|
|
return [
|
|
shared_library_info,
|
|
cxx_resource_info,
|
|
# Add an unused default output in case this target is used an an attr.source() anywhere.
|
|
DefaultInfo(default_outputs = [ctx.actions.write("unused.jar", [])]),
|
|
TemplatePlaceholderInfo(keyed_variables = {
|
|
"classpath": "unused_but_needed_for_analysis",
|
|
}),
|
|
]
|
|
|
|
java_providers = build_kotlin_library(ctx)
|
|
return to_list(java_providers) + [
|
|
# TODO(T107163344) this shouldn't be in kotlin_library itself, use overlays to remove it.
|
|
merge_android_packageable_info(
|
|
ctx.label,
|
|
ctx.actions,
|
|
ctx.attrs.deps + ctx.attrs.exported_deps + ctx.attrs.runtime_deps,
|
|
),
|
|
]
|
|
|
|
def build_kotlin_library(
|
|
ctx: "context",
|
|
additional_classpath_entries: ["artifact"] = [],
|
|
bootclasspath_entries: ["artifact"] = []) -> "JavaProviders":
|
|
srcs = ctx.attrs.srcs
|
|
has_kotlin_srcs = any([src.extension == ".kt" or src.basename.endswith(".src.zip") or src.basename.endswith("-sources.jar") for src in srcs])
|
|
|
|
if not has_kotlin_srcs:
|
|
return build_java_library(
|
|
ctx,
|
|
ctx.attrs.srcs,
|
|
bootclasspath_entries = bootclasspath_entries,
|
|
additional_classpath_entries = additional_classpath_entries,
|
|
# Match buck1, which always does class ABI generation for Kotlin targets unless explicitly specified.
|
|
override_abi_generation_mode = get_abi_generation_mode(ctx.attrs.abi_generation_mode) or AbiGenerationMode("class"),
|
|
)
|
|
|
|
else:
|
|
deps_query = getattr(ctx.attrs, "deps_query", []) or []
|
|
provided_deps_query = getattr(ctx.attrs, "provided_deps_query", []) or []
|
|
deps = (
|
|
ctx.attrs.deps +
|
|
deps_query +
|
|
ctx.attrs.exported_deps +
|
|
ctx.attrs.provided_deps +
|
|
provided_deps_query +
|
|
ctx.attrs.exported_provided_deps
|
|
)
|
|
annotation_processor_params = create_ap_params(
|
|
ctx,
|
|
ctx.attrs.plugins,
|
|
ctx.attrs.annotation_processors,
|
|
ctx.attrs.annotation_processor_params,
|
|
ctx.attrs.annotation_processor_deps,
|
|
)
|
|
ksp_annotation_processor_params = create_ksp_ap_params(ctx, ctx.attrs.plugins)
|
|
|
|
kotlin_toolchain = ctx.attrs._kotlin_toolchain[KotlinToolchainInfo]
|
|
if kotlin_toolchain.kotlinc_protocol == "classic":
|
|
kotlinc_classes, kapt_generated_sources, ksp_generated_sources = _create_kotlin_sources(
|
|
ctx,
|
|
ctx.attrs.srcs,
|
|
deps,
|
|
annotation_processor_params,
|
|
ksp_annotation_processor_params,
|
|
# kotlic doesn't support -bootclasspath param, so adding `bootclasspath_entries` into kotlin classpath
|
|
additional_classpath_entries + bootclasspath_entries,
|
|
)
|
|
srcs = [src for src in ctx.attrs.srcs if not src.extension == ".kt"]
|
|
if kapt_generated_sources:
|
|
srcs.append(kapt_generated_sources)
|
|
if ksp_generated_sources:
|
|
srcs.append(ksp_generated_sources)
|
|
java_lib = build_java_library(
|
|
ctx,
|
|
srcs,
|
|
run_annotation_processors = False,
|
|
bootclasspath_entries = bootclasspath_entries,
|
|
additional_classpath_entries = [kotlinc_classes] + additional_classpath_entries,
|
|
additional_compiled_srcs = kotlinc_classes,
|
|
generated_sources = filter(None, [kapt_generated_sources, ksp_generated_sources]),
|
|
)
|
|
return java_lib
|
|
elif kotlin_toolchain.kotlinc_protocol == "kotlincd":
|
|
source_level, target_level = get_java_version_attributes(ctx)
|
|
outputs = create_jar_artifact_kotlincd(
|
|
actions = ctx.actions,
|
|
actions_prefix = "",
|
|
abi_generation_mode = get_abi_generation_mode(ctx.attrs.abi_generation_mode),
|
|
java_toolchain = ctx.attrs._java_toolchain[JavaToolchainInfo],
|
|
kotlin_toolchain = kotlin_toolchain,
|
|
label = ctx.label,
|
|
srcs = srcs,
|
|
remove_classes = ctx.attrs.remove_classes,
|
|
resources = ctx.attrs.resources,
|
|
resources_root = ctx.attrs.resources_root,
|
|
ap_params = annotation_processor_params + ([ksp_annotation_processor_params] if ksp_annotation_processor_params else []),
|
|
plugin_params = create_plugin_params(ctx, ctx.attrs.plugins),
|
|
source_level = source_level,
|
|
target_level = target_level,
|
|
deps = deps,
|
|
required_for_source_only_abi = ctx.attrs.required_for_source_only_abi,
|
|
source_only_abi_deps = ctx.attrs.source_only_abi_deps,
|
|
extra_arguments = ctx.attrs.extra_arguments,
|
|
additional_classpath_entries = additional_classpath_entries,
|
|
bootclasspath_entries = bootclasspath_entries,
|
|
is_building_android_binary = ctx.attrs._is_building_android_binary,
|
|
friend_paths = ctx.attrs.friend_paths,
|
|
kotlin_compiler_plugins = ctx.attrs.kotlin_compiler_plugins,
|
|
extra_kotlinc_arguments = ctx.attrs.extra_kotlinc_arguments,
|
|
)
|
|
|
|
java_library_info, java_packaging_info, shared_library_info, cxx_resource_info, template_placeholder_info, intellij_info = create_java_library_providers(
|
|
ctx,
|
|
library_output = outputs.classpath_entry if outputs else None,
|
|
declared_deps = ctx.attrs.deps + deps_query,
|
|
exported_deps = ctx.attrs.exported_deps,
|
|
provided_deps = ctx.attrs.provided_deps + provided_deps_query,
|
|
exported_provided_deps = ctx.attrs.exported_provided_deps,
|
|
runtime_deps = ctx.attrs.runtime_deps,
|
|
needs_desugar = source_level > 7 or target_level > 7,
|
|
generated_sources = [outputs.annotation_processor_output] if outputs and outputs.annotation_processor_output else [],
|
|
)
|
|
|
|
default_info = get_default_info(outputs)
|
|
return JavaProviders(
|
|
java_library_info = java_library_info,
|
|
java_library_intellij_info = intellij_info,
|
|
java_packaging_info = java_packaging_info,
|
|
shared_library_info = shared_library_info,
|
|
cxx_resource_info = cxx_resource_info,
|
|
template_placeholder_info = template_placeholder_info,
|
|
default_info = default_info,
|
|
)
|
|
else:
|
|
fail("unrecognized kotlinc protocol `{}`".format(kotlin_toolchain.kotlinc_protocol))
|