blob: 2b950634164a491c41f51c8528df51b79ced889d [file] [log] [blame]
# Copyright 2022 Google LLC. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the License);
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
"""Kotlin kt_jvm_library rule."""
load("//bazel:stubs.bzl", "register_extension_info")
load("//:visibility.bzl", "RULES_KOTLIN")
load("//kotlin:compiler_opt.bzl", "kotlincopts_attrs", "merge_kotlincopts")
load("//kotlin/common/providers:compiler_plugin_infos.bzl", "kt_compiler_plugin_infos")
load("//toolchains/kotlin_jvm:androidlint_toolchains.bzl", "androidlint_toolchains")
load("//toolchains/kotlin_jvm:java_toolchains.bzl", "java_toolchains")
load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains")
load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("//bazel:stubs.bzl", "lint_actions")
load("//bazel:stubs.bzl", "LINT_REGISTRY")
load("//bazel:stubs.bzl", "registry_checks_for_package")
load(":common.bzl", "common")
load(":jvm_compile.bzl", "kt_jvm_compile")
load(":traverse_exports.bzl", "kt_traverse_exports")
visibility(RULES_KOTLIN)
def kt_jvm_library(
name,
srcs = None,
common_srcs = None,
data = None,
exports = None,
deps = None,
runtime_deps = None,
proguard_specs = None,
plugins = None,
exported_plugins = None,
resources = None,
tags = None,
javacopts = None,
custom_kotlincopts = None,
disable_lint_checks = None,
transitive_configs = None,
**kwargs):
"""This rule compiles Kotlin (and Java) sources into a Jar file.
Most Java-like libraries and binaries can depend on this rule, and this rule can in turn depend
on Kotlin and Java libraries. This rule supports a subset of attributes supported by
`java_library`. In addition to documentation provided as part of this rule, please also refer to
their documentation as part of `java_library`.
Args:
name: Name of the target.
srcs: A list of sources to compile.
common_srcs: A list of common sources to compile for multi-platform projects.
data: A list of data dependencies.
exports: A list of targets to export to rules that depend on this one.
deps: A list of dependencies.
runtime_deps: Libraries to make available to the final binary or test at runtime only.
proguard_specs: Proguard specifications to go along with this library.
plugins: Java annotation processors to run at compile-time.
exported_plugins: https://bazel.build/reference/be/java#java_plugin rules to export to direct
dependencies.
resources: A list of data files to include in the Jar, see
https://bazel.build/reference/be/java#java_library.resources.
tags: A list of string tags passed to generated targets.
testonly: Whether this target is intended only for tests.
javacopts: Additional flags to pass to javac if used.
custom_kotlincopts: Additional flags to pass to Kotlin compiler.
disable_lint_checks: A list of AndroidLint checks to be skipped.
transitive_configs: Blaze feature flags (if any) on which this target depends.
deprecation: Standard attribute, see
https://bazel.build/reference/be/common-definitions#common.deprecation.
features: Features enabled.
**kwargs: Other keyword arguments.
"""
# Helps go/build_cleaner to identify the targets generated by the macro.
tags = (tags or []) + ["kt_jvm_library"]
kt_jvm_library_helper(
name = name,
srcs = srcs,
common_srcs = common_srcs,
deps = deps,
exports = exports,
runtime_deps = runtime_deps,
plugins = plugins,
exported_plugins = exported_plugins,
resources = resources,
javacopts = javacopts,
custom_kotlincopts = custom_kotlincopts,
proguard_specs = proguard_specs,
data = data,
disable_lint_checks = disable_lint_checks,
tags = tags,
transitive_configs = transitive_configs,
**dicts.add(
kwargs,
{
# Dictionary necessary to set private attributes.
"$android_lint_baseline_file": lint_actions.get_android_lint_baseline_file(native.package_name()),
"$android_lint_plugins": registry_checks_for_package(LINT_REGISTRY, native.package_name()),
},
)
)
register_extension_info(
extension = kt_jvm_library,
label_regex_for_dep = "{extension_name}",
)
# TODO: Rename this to _kmp_jvm_library
kt_jvm_library_helper = rule(
implementation = lambda ctx: _kt_jvm_library_helper_impl(ctx),
doc = """This rule compiles Kotlin (and Java) sources into a Jar file. Most Java-like libraries
and binaries can depend on this rule, and this rule can in turn depend on Kotlin and
Java libraries. This rule supports a subset of attributes supported by `java_library`.
In addition to documentation provided as part of this rule, please also refer to their
documentation as part of `java_library`.""",
attrs = dicts.add(
androidlint_toolchains.attrs,
java_toolchains.attrs,
kotlincopts_attrs(),
kt_jvm_toolchains.attrs,
common_srcs = attr.label_list(
allow_files = common.KT_FILE_TYPES,
allow_empty = True,
doc = """The list of common multi-platform source files that are processed to create
the target.""",
),
data = attr.label_list(
allow_files = True,
),
deps = attr.label_list(
providers = [
# Each provider-set expands on allow_rules
[JavaInfo],
],
aspects = [
kt_traverse_exports.aspect,
],
doc = """The list of libraries this library directly depends on at compile-time. For Java
and Kotlin libraries listed, the Jars they build as well as the transitive closure
of their `deps` and `exports` will be on the compile-time classpath for this rule;
also, the transitive closure of their `deps`, `runtime_deps`, and `exports` will be
on the runtime classpath (excluding dependencies only depended on as `neverlink`).
Note on strict_deps: any Java type explicitly or implicitly referred to in `srcs`
must be included here. This is a stronger requirement than what is enforced for
`java_library`. Any build failures resulting from this requirement will include the
missing dependencies and a command to fix the rule.""",
),
disable_lint_checks = attr.string_list(
doc = """A list of lint checks to be skipped for this target.""",
),
exported_plugins = attr.label_list(
providers = [
[JavaPluginInfo],
[kt_compiler_plugin_infos.Info],
[lint_actions.AndroidLintRulesetInfo],
],
cfg = "exec",
doc = """JVM plugins to export to users.
Every plugin listed will run during compliations that depend on this target, as
if it were listed directly in that target's `plugins` attribute. `java_*` targets
will not run kotlinc plugins""",
),
exports = attr.label_list(
providers = [
# Each provider-set expands on allow_rules
[JavaInfo],
],
aspects = [
kt_traverse_exports.aspect,
],
doc = """List of libraries treated as if they were part of this library by upstream
Java/Kotlin dependencies, see go/be-java#java_library.exports. These libraries
are **not** automatically also dependencies of this library.""",
),
javacopts = attr.string_list(
doc = """Additional flags to pass to javac if used as part of this rule, which is the case
if `.java` `srcs` are provided or annotation processors generate sources for this
rule.""",
),
neverlink = attr.bool(
default = False,
doc = """Only use this library for compilation and not at runtime. Useful if the library
will be provided by the runtime environment during execution.""",
),
plugins = attr.label_list(
providers = [
[JavaPluginInfo],
[kt_compiler_plugin_infos.Info],
[lint_actions.AndroidLintRulesetInfo],
],
cfg = "exec",
doc = """JVM plugins to run during compilation.
Every plugin listed will run whenever this library is built. Resources generated by the
plugin will be included in the output JAR. A library may also inherit plugins from
dependencies that use `exported_plugins`.""",
),
proguard_specs = attr.label_list(
allow_files = True,
doc = """Proguard specifications to go along with this library.""",
),
resources = attr.label_list(
allow_files = True,
doc = """A list of data files to include in the Jar, see
go/be#java_library.resources.""",
),
runtime_deps = attr.label_list(
providers = [
# Each provider-set expands on allow_rules
[JavaInfo],
[CcInfo], # for JNI / native dependencies
],
aspects = [
kt_traverse_exports.aspect,
],
doc = """Runtime-only dependencies.""",
),
srcs = attr.label_list(
allow_files = common.KT_JVM_FILE_TYPES,
allow_empty = True,
doc = """The list of source files that are processed to create the target.
To support circular dependencies, this can include `.kt` and `.java` files.""",
),
_android_lint_plugins = attr.label_list(
providers = [lint_actions.AndroidLintRulesetInfo],
cfg = "exec",
doc = """Additional Android Lint checks to run at compile-time.""",
),
),
fragments = ["java"],
outputs = dict(
jar = "lib%{name}.jar",
srcjar = "lib%{name}-src.jar", # implicit declared output for consistency with java_library
),
provides = [JavaInfo],
toolchains = [kt_jvm_toolchains.type, "@bazel_tools//tools/jdk:toolchain_type"],
)
def _kt_jvm_library_helper_impl(ctx):
kt_jvm_toolchain = kt_jvm_toolchains.get(ctx)
for target in ctx.attr.runtime_deps:
if (JavaInfo not in target) and (CcInfo not in target):
fail("Unexpected runtime dependency (must provide JavaInfo or CcInfo): " + str(target.label))
if not ctx.files.srcs and not ctx.files.common_srcs and not ctx.attr.exports and not ctx.attr.exported_plugins:
fail("Expected a source-bearing or an export-oriented target:\n" +
"One of {srcs, common_srcs, exports, exported_plugins} of target %s must be non empty" % ctx.label)
compile_result = kt_jvm_compile(
ctx,
output = ctx.outputs.jar,
srcs = ctx.files.srcs,
common_srcs = ctx.files.common_srcs,
deps = ctx.attr.deps,
plugins = ctx.attr.plugins,
exported_plugins = ctx.attr.exported_plugins,
runtime_deps = ctx.attr.runtime_deps,
exports = ctx.attr.exports,
javacopts = ctx.attr.javacopts,
kotlincopts = merge_kotlincopts(ctx),
neverlink = ctx.attr.neverlink,
testonly = ctx.attr.testonly,
android_lint_plugins = ctx.attr._android_lint_plugins,
manifest = None,
merged_manifest = None,
resource_files = [],
classpath_resources = ctx.files.resources,
kt_toolchain = kt_jvm_toolchain,
java_toolchain = java_toolchains.get(ctx),
disable_lint_checks = ctx.attr.disable_lint_checks,
rule_family = common.RULE_FAMILY.JVM_LIBRARY,
)
java_info = compile_result.java_info
# Collect and validate proguard_specs
# TODO should also propagate IDL proguard_specs when there's idl_srcs
transitive_proguard_configs = common.collect_proguard_specs(
ctx,
ctx.files.proguard_specs,
ctx.attr.deps + ctx.attr.exports,
kt_jvm_toolchain.proguard_whitelister,
)
# Create OutputGroupInfo
output_groups = dict(
_validation = depset(compile_result.validations),
_source_jars = depset(
java_info.source_jars,
transitive = [java_info.transitive_source_jars],
),
_direct_source_jars = depset(java_info.source_jars),
_hidden_top_level_INTERNAL_ = depset(
transitive = [
info._hidden_top_level_INTERNAL_
for info in common.collect_providers(
OutputGroupInfo,
ctx.attr.deps + ctx.attr.exports,
)
] + [transitive_proguard_configs],
),
)
return [
java_info,
ProguardSpecProvider(transitive_proguard_configs),
_make_default_info(
ctx,
[ctx.outputs.jar],
propagated_attrs = ctx.attr.deps + ctx.attr.runtime_deps + ctx.attr.exports,
),
OutputGroupInfo(**output_groups),
coverage_common.instrumented_files_info(
ctx,
source_attributes = ["srcs", "common_srcs"],
dependency_attributes = ["data", "deps", "resources", "runtime_deps"],
),
]
# TODO: Use this function in all Kotlin rules
def _make_default_info(ctx, direct_files, propagated_attrs):
# Collect runfiles from deps
transitive_runfiles = []
for p in common.collect_providers(DefaultInfo, propagated_attrs):
transitive_runfiles.append(p.data_runfiles.files)
transitive_runfiles.append(p.default_runfiles.files)
runfiles = ctx.runfiles(
files = direct_files,
transitive_files = depset(transitive = transitive_runfiles),
collect_default = True, # handles data attribute
)
return DefaultInfo(
files = depset(direct_files),
runfiles = runfiles,
)