From 0c869513dcc9d473cc66375ffabc69d5ceb2e47b Mon Sep 17 00:00:00 2001 From: Christian Gruber Date: Fri, 4 Oct 2019 15:52:58 -0700 Subject: [PATCH] Add support for friend declarations of a library or test on another compilation unit, causing it to (a) share a module definition, and (b) have access to the internal members of that library. This expands the current feature which exposes this to test only, and generalizes it. Also, the dagger example is partitioned into smaller pieces, to illustrate and validate the use of friend declarations, directly and transitively. --- .bazelci/presubmit.yml | 12 +++++- README.md | 41 ++++++++++++++++++- examples/dagger/BUILD.bazel | 21 ++++++++++ .../dagger/{BUILD => src/coffee/BUILD.bazel} | 16 ++++---- examples/dagger/src/coffee/CoffeeMaker.kt | 7 +++- .../dagger/src/coffee/DripCoffeeModule.kt | 21 ++++++++-- examples/dagger/src/heating/BUILD.bazel | 24 +++++++++++ examples/dagger/src/heating/ElectricHeater.kt | 40 ++++++++++++++++++ .../dagger/src/{coffee => heating}/Heater.kt | 13 +++--- examples/dagger/src/pumping/BUILD.bazel | 26 ++++++++++++ .../dagger/src/{coffee => pumping}/Pump.kt | 2 +- .../src/{coffee => pumping}/PumpModule.kt | 4 +- .../src/{coffee => pumping}/Thermosiphon.kt | 10 +++-- examples/dagger/src/time/BUILD.bazel | 20 +++++++++ .../ElectricHeater.kt => time/Delayer.kt} | 16 ++------ examples/dagger/test/coffee/BUILD.bazel | 22 ++++++++++ examples/dagger/test/coffee/BasicTest.kt | 21 ++++++++++ examples/dagger/test/coffee/BasicTestUtil.kt | 5 +++ kotlin/internal/defs.bzl | 1 + kotlin/internal/jvm/android.bzl | 7 +++- kotlin/internal/jvm/compile.bzl | 22 ++++++++-- kotlin/internal/jvm/jvm.bzl | 19 ++++++--- 22 files changed, 318 insertions(+), 52 deletions(-) create mode 100644 examples/dagger/BUILD.bazel rename examples/dagger/{BUILD => src/coffee/BUILD.bazel} (83%) create mode 100644 examples/dagger/src/heating/BUILD.bazel create mode 100644 examples/dagger/src/heating/ElectricHeater.kt rename examples/dagger/src/{coffee => heating}/Heater.kt (79%) create mode 100644 examples/dagger/src/pumping/BUILD.bazel rename examples/dagger/src/{coffee => pumping}/Pump.kt (97%) rename examples/dagger/src/{coffee => pumping}/PumpModule.kt (93%) rename examples/dagger/src/{coffee => pumping}/Thermosiphon.kt (79%) create mode 100644 examples/dagger/src/time/BUILD.bazel rename examples/dagger/src/{coffee/ElectricHeater.kt => time/Delayer.kt} (73%) create mode 100644 examples/dagger/test/coffee/BUILD.bazel create mode 100644 examples/dagger/test/coffee/BasicTest.kt create mode 100644 examples/dagger/test/coffee/BasicTestUtil.kt diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 8bcc40ca1..ef9ca9e8e 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -7,11 +7,15 @@ tasks: - "//:rules_kotlin_release" test_targets: - "//:all_tests" + - "//examples/dagger/..." + - "//examples/plugin/..." ubuntu1804: - test_targets: - - "//:all_tests" build_targets: - "//:rules_kotlin_release" + test_targets: + - "//:all_tests" + - "//examples/dagger/..." + - "//examples/plugin/..." rbe_ubuntu1604: test_targets: - "--" @@ -20,6 +24,8 @@ tasks: # execution compatible, do not run them for now. - "//src/test/kotlin/io/bazel/kotlin:KotlinJvmFriendsVisibilityTest" - "//src/test/kotlin/io/bazel/kotlin:KotlinJvmBasicAssertionTest" + - "//examples/dagger/..." + - "//examples/plugin/..." test_flags: # Override the default worker strategy for remote builds (worker strategy # cannot be used with remote builds) @@ -27,6 +33,8 @@ tasks: macos: test_targets: - "//:all_tests" + - "//examples/dagger/..." + - "//examples/plugin/..." example-android: name: "Example - Android" platform: ubuntu1804 diff --git a/README.md b/README.md index c114caffa..eedfbfe00 100644 --- a/README.md +++ b/README.md @@ -124,8 +124,8 @@ in your `WORKSPACE` file (or import from a `.bzl` file: ```python load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories") -KOTLIN_VERSION = "1.3.31" -KOTLINC_RELEASE_SHA = "107325d56315af4f59ff28db6837d03c2660088e3efeb7d4e41f3e01bb848d6a" +KOTLIN_VERSION = "1.3.50" +KOTLINC_RELEASE_SHA = "69424091a6b7f52d93eed8bba2ace921b02b113dbb71388d704f8180a6bdc6ec" KOTLINC_RELEASE = { "urls": [ @@ -161,6 +161,43 @@ kotlin_repositories() # if you want the default. Otherwise see custom kotlinc di kt_register_toolchains() # to use the default toolchain, otherwise see toolchains below ``` +## Friends/Internal support + +The rules support kotlin `internal` visibility (usually accessible only to the compilation unit) +by allowing a library or test to specify that it is friends with another library like so: + +``` +kt_jvm_library( + name = "foo", + srcs = glob(["*.kt"]), + friend = "//some/other:target", + # ... +) +``` + +> Note: declaring friends of a kt_android_library requires adding `_kt` to the target, e.g. +> `//some/other:target_kt`. This is because the `kt_android_library` rule is a macro with a +> `kt_jvm_library` under the hood, and the surfaced rule is an android rule which doesn't have +> kotlin aware bazel providers. This will be fixed in the future. + +This grants access to `internal` members of `//some/other:target`. A library can only be friends +with one other library, which must be a kotlin-aware target. It inherits the module name from that +library. Only one friend can be declared, because of the assumptions made here about module +membership. Since friendship can be transitive (see below), this constrains the visibility so it +does not become an arbitrarily growing lattice of trust, defeating the purpose. + +Very common use-cases for this are: + + * tests and test-libraries depending on internals of the system under test. + * clusters of targets that represent one logical unit, with public, private, + fake, testing-utilities, configuration, or other targets that comprise the + whole unit. + +Friendship has limited transitivity. Consider projects `C`, `B`, and `A` with a dependency +relationship `C->B->A`. If `C` declares friendship in `B`, and `B` declares friendship with `A`, +then they are all treated as logically one module for `internal` purposes. However it doesn't +skip. Once the line of friendship is broken, a separate module is presumed by kotlinc. + # Kotlin compiler plugins The `kt_compiler_plugin` rule allows running Kotlin compiler plugins, such as no-arg, sam-with-receiver and allopen. diff --git a/examples/dagger/BUILD.bazel b/examples/dagger/BUILD.bazel new file mode 100644 index 000000000..d24199900 --- /dev/null +++ b/examples/dagger/BUILD.bazel @@ -0,0 +1,21 @@ +# Copyright 2018 The Bazel Authors. 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. +package(default_visibility = ["//examples/dagger:__subpackages__"]) + +java_binary( + name = "coffee_app", + main_class = "coffee.CoffeeApp", + visibility = ["//visibility:public"], + runtime_deps = ["//examples/dagger/src/coffee"], +) diff --git a/examples/dagger/BUILD b/examples/dagger/src/coffee/BUILD.bazel similarity index 83% rename from examples/dagger/BUILD rename to examples/dagger/src/coffee/BUILD.bazel index 1d567601d..9ee1bdf82 100644 --- a/examples/dagger/BUILD +++ b/examples/dagger/src/coffee/BUILD.bazel @@ -35,20 +35,18 @@ rm TeaPot.kt ) kt_jvm_library( - name = "coffee_lib", - srcs = glob(["src/**"]) + [ + name = "coffee", + srcs = glob(["*.kt"]) + [ # Adding a file ending with .srcjar is how code generation patterns are implemented. ":tea_lib_src", ], + friend = "//examples/dagger/src/pumping", + visibility = ["//examples/dagger:__subpackages__"], deps = [ + "//examples/dagger/src/heating", + "//examples/dagger/src/pumping", + "//examples/dagger/src/time", "//third_party:dagger", "@kotlin_rules_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core", ], ) - -java_binary( - name = "coffee_app", - main_class = "coffee.CoffeeApp", - visibility = ["//visibility:public"], - runtime_deps = [":coffee_lib"], -) diff --git a/examples/dagger/src/coffee/CoffeeMaker.kt b/examples/dagger/src/coffee/CoffeeMaker.kt index 270eb1efb..817825772 100644 --- a/examples/dagger/src/coffee/CoffeeMaker.kt +++ b/examples/dagger/src/coffee/CoffeeMaker.kt @@ -16,9 +16,11 @@ package coffee import dagger.Lazy +import heating.Heater +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import javax.inject.Inject +import pumping.Pump class CoffeeMaker @Inject internal constructor( // Create a possibly costly heater only when we use it. @@ -34,5 +36,8 @@ class CoffeeMaker @Inject internal constructor( println(" [_]P coffee! [_]P ") heater.get().off() } + withContext(Dispatchers.Default) { + if (heater.get().isOn) throw IllegalStateException("Heater should be off") + } } } diff --git a/examples/dagger/src/coffee/DripCoffeeModule.kt b/examples/dagger/src/coffee/DripCoffeeModule.kt index 42bddbc33..e0f0e81c4 100644 --- a/examples/dagger/src/coffee/DripCoffeeModule.kt +++ b/examples/dagger/src/coffee/DripCoffeeModule.kt @@ -15,15 +15,30 @@ */ package coffee +import dagger.Binds import dagger.Module import dagger.Provides +import heating.ElectricHeater +import heating.Heater import javax.inject.Singleton +import pumping.PumpModule +import time.Delayer -@Module(includes = arrayOf(PumpModule::class)) +@Module(includes = arrayOf(PumpModule::class, Bindings::class)) internal class DripCoffeeModule { @Provides @Singleton - fun provideHeater(): Heater { - return ElectricHeater() + fun provideDelayer(): Delayer { + return object : Delayer { + override fun delay() { + Thread.sleep(1000) + } + } } } + +@Module +internal abstract class Bindings { + @Binds @Singleton + internal abstract fun bindHeater(heater: ElectricHeater): Heater +} diff --git a/examples/dagger/src/heating/BUILD.bazel b/examples/dagger/src/heating/BUILD.bazel new file mode 100644 index 000000000..26e726172 --- /dev/null +++ b/examples/dagger/src/heating/BUILD.bazel @@ -0,0 +1,24 @@ +# Copyright 2019 The Bazel Authors. 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. +load("//kotlin:kotlin.bzl", "kt_jvm_library") + +kt_jvm_library( + name = "heating", + srcs = glob(["*.kt"]), + visibility = ["//examples/dagger:__subpackages__"], + deps = [ + "//examples/dagger/src/time", + "//third_party:dagger", + ], +) diff --git a/examples/dagger/src/heating/ElectricHeater.kt b/examples/dagger/src/heating/ElectricHeater.kt new file mode 100644 index 000000000..c9a53ac16 --- /dev/null +++ b/examples/dagger/src/heating/ElectricHeater.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2018 The Bazel Authors. 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. + */ +package heating + +import javax.inject.Inject +import time.Delayer + +class ElectricHeater + @Inject constructor(private val delayer: Delayer) : Heater() { + + override var isHot: Boolean = false + override var isOn: Boolean = false + + override fun on() { + isOn = true + println("~ ~ ~ heating ~ ~ ~") + delayer.delay() + this.isHot = true + } + + override fun off() { + this.isOn = false + println("~ ~ ~ cooling ~ ~ ~") + delayer.delay() + this.isHot = false + } +} diff --git a/examples/dagger/src/coffee/Heater.kt b/examples/dagger/src/heating/Heater.kt similarity index 79% rename from examples/dagger/src/coffee/Heater.kt rename to examples/dagger/src/heating/Heater.kt index d4eb52bac..9db0e6e3c 100644 --- a/examples/dagger/src/coffee/Heater.kt +++ b/examples/dagger/src/heating/Heater.kt @@ -13,10 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package coffee +package heating -internal interface Heater { - val isHot: Boolean - fun on() - fun off() +abstract class Heater { + abstract val isHot: Boolean + + internal abstract val isOn: Boolean + + abstract fun on() + abstract fun off() } diff --git a/examples/dagger/src/pumping/BUILD.bazel b/examples/dagger/src/pumping/BUILD.bazel new file mode 100644 index 000000000..6a1abb7e5 --- /dev/null +++ b/examples/dagger/src/pumping/BUILD.bazel @@ -0,0 +1,26 @@ +# Copyright 2019 The Bazel Authors. 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. +load("//kotlin:kotlin.bzl", "kt_jvm_library") + +kt_jvm_library( + name = "pumping", + srcs = glob(["*.kt"]), + visibility = ["//examples/dagger:__subpackages__"], + friend = "//examples/dagger/src/heating", + deps = [ + "//examples/dagger/src/heating", + "//examples/dagger/src/time", + "//third_party:dagger", + ], +) diff --git a/examples/dagger/src/coffee/Pump.kt b/examples/dagger/src/pumping/Pump.kt similarity index 97% rename from examples/dagger/src/coffee/Pump.kt rename to examples/dagger/src/pumping/Pump.kt index e695cc22b..2860de015 100644 --- a/examples/dagger/src/coffee/Pump.kt +++ b/examples/dagger/src/pumping/Pump.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package coffee +package pumping internal interface Pump { fun pump() diff --git a/examples/dagger/src/coffee/PumpModule.kt b/examples/dagger/src/pumping/PumpModule.kt similarity index 93% rename from examples/dagger/src/coffee/PumpModule.kt rename to examples/dagger/src/pumping/PumpModule.kt index 304c3e217..5d0c0f39a 100644 --- a/examples/dagger/src/coffee/PumpModule.kt +++ b/examples/dagger/src/pumping/PumpModule.kt @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package coffee +package pumping import dagger.Binds import dagger.Module @Module -internal abstract class PumpModule { +abstract class PumpModule { @Binds internal abstract fun providePump(pump: Thermosiphon): Pump } diff --git a/examples/dagger/src/coffee/Thermosiphon.kt b/examples/dagger/src/pumping/Thermosiphon.kt similarity index 79% rename from examples/dagger/src/coffee/Thermosiphon.kt rename to examples/dagger/src/pumping/Thermosiphon.kt index cea1253e4..619eeb311 100644 --- a/examples/dagger/src/coffee/Thermosiphon.kt +++ b/examples/dagger/src/pumping/Thermosiphon.kt @@ -13,16 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package coffee +package pumping +import heating.Heater import javax.inject.Inject +import time.Delayer -internal class Thermosiphon @Inject -constructor(private val heater: Heater) : Pump { +internal class Thermosiphon + @Inject constructor(private val heater: Heater, private val delayer: Delayer) : + Pump { override fun pump() { if (heater.isHot) { println("=> => pumping => =>") + delayer.delay() } } } diff --git a/examples/dagger/src/time/BUILD.bazel b/examples/dagger/src/time/BUILD.bazel new file mode 100644 index 000000000..f358b6371 --- /dev/null +++ b/examples/dagger/src/time/BUILD.bazel @@ -0,0 +1,20 @@ +# Copyright 2019 The Bazel Authors. 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. +load("//kotlin:kotlin.bzl", "kt_jvm_library") + +kt_jvm_library( + name = "time", + srcs = glob(["*.kt"]), + visibility = ["//examples/dagger:__subpackages__"], +) diff --git a/examples/dagger/src/coffee/ElectricHeater.kt b/examples/dagger/src/time/Delayer.kt similarity index 73% rename from examples/dagger/src/coffee/ElectricHeater.kt rename to examples/dagger/src/time/Delayer.kt index 32cd9eea7..f8cfd6552 100644 --- a/examples/dagger/src/coffee/ElectricHeater.kt +++ b/examples/dagger/src/time/Delayer.kt @@ -13,17 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package coffee +package time -internal class ElectricHeater : Heater { - override var isHot: Boolean = false - - override fun on() { - println("~ ~ ~ heating ~ ~ ~") - this.isHot = true - } - - override fun off() { - this.isHot = false - } +/** Introduces a delay (which can be overridden in testing */ +interface Delayer { + fun delay(): Unit } diff --git a/examples/dagger/test/coffee/BUILD.bazel b/examples/dagger/test/coffee/BUILD.bazel new file mode 100644 index 000000000..7d4c2b63f --- /dev/null +++ b/examples/dagger/test/coffee/BUILD.bazel @@ -0,0 +1,22 @@ +load("//kotlin:kotlin.bzl", "kt_jvm_library", "kt_jvm_test") + +kt_jvm_library( + name = "testlib", + srcs = ["BasicTestUtil.kt"], + friend = "//examples/dagger/src/heating", + deps = [ + "//examples/dagger/src/heating", + ], +) + +kt_jvm_test( + name = "BasicTest", + srcs = ["BasicTest.kt"], + friends = [":testlib"], # old syntax + deps = [ + ":testlib", + "//examples/dagger/src/heating", + "@kotlin_rules_maven//:com_google_truth_truth", + "@kotlin_rules_maven//:junit_junit", + ], +) diff --git a/examples/dagger/test/coffee/BasicTest.kt b/examples/dagger/test/coffee/BasicTest.kt new file mode 100644 index 000000000..9001604c1 --- /dev/null +++ b/examples/dagger/test/coffee/BasicTest.kt @@ -0,0 +1,21 @@ +package coffee + +import com.google.common.truth.Truth.assertThat +import heating.ElectricHeater +import org.junit.Test +import time.Delayer + +class BasicTest { + @Test fun `test that internal member is transitively visible`() { + val heater = ElectricHeater(object : Delayer { + override fun delay() { + println("fake delay") + } + }) + assertThat(isHeaterOn(heater)).isFalse() + heater.on() + assertThat(isHeaterOn(heater)).isTrue() + heater.off() + assertThat(heater.isOn).isFalse() + } +} diff --git a/examples/dagger/test/coffee/BasicTestUtil.kt b/examples/dagger/test/coffee/BasicTestUtil.kt new file mode 100644 index 000000000..2a6f01d8e --- /dev/null +++ b/examples/dagger/test/coffee/BasicTestUtil.kt @@ -0,0 +1,5 @@ +package coffee + +import heating.Heater + +internal fun isHeaterOn(heater: Heater): Boolean = heater.isOn diff --git a/kotlin/internal/defs.bzl b/kotlin/internal/defs.bzl index 2fe00b70d..ffbdaab4d 100644 --- a/kotlin/internal/defs.bzl +++ b/kotlin/internal/defs.bzl @@ -21,6 +21,7 @@ KT_COMPILER_REPO = "com_github_jetbrains_kotlin" KtJvmInfo = provider( fields = { "module_name": "the module name", + "friend_paths": "The target(s) that this library can see the internals of.", "srcs": "the source files. [intelij-aspect]", "outputs": "output jars produced by this rule. [intelij-aspect]", "language_version": "version of kotlin used. [intellij-aspect]", diff --git a/kotlin/internal/jvm/android.bzl b/kotlin/internal/jvm/android.bzl index 87c2d6af3..a6f818a8b 100644 --- a/kotlin/internal/jvm/android.bzl +++ b/kotlin/internal/jvm/android.bzl @@ -16,7 +16,7 @@ load( _kt_jvm_library = "kt_jvm_library", ) -def _kt_android_artifact(name, srcs = [], deps = [], plugins = [], **kwargs): +def _kt_android_artifact(name, srcs = [], deps = [], plugins = [], friend = None, **kwargs): """Delegates Android related build attributes to the native rules but uses the Kotlin builder to compile Java and Kotlin srcs. Returns a sequence of labels that a wrapping macro should export. """ @@ -38,7 +38,10 @@ def _kt_android_artifact(name, srcs = [], deps = [], plugins = [], **kwargs): deps = base_deps + [base_name], plugins = plugins, testonly = kwargs.get("testonly", default = 0), - visibility = ["//visibility:private"], + friend = friend, + # must be public to be referenced as friends. + # TODO: rework this into a proper android provider giving rule, so we can avoid all this. + visibility = ["//visibility:public"], ) return [base_name, kt_name] diff --git a/kotlin/internal/jvm/compile.bzl b/kotlin/internal/jvm/compile.bzl index 272272e09..fc6d35410 100644 --- a/kotlin/internal/jvm/compile.bzl +++ b/kotlin/internal/jvm/compile.bzl @@ -164,26 +164,39 @@ def _compiler_toolchains(ctx): def _compiler_friends(ctx, friends): """Creates a struct of friends meta data""" - # TODO extract and move this into common. Need to make it generic first. + # Handle backward compatibility + friend = getattr(ctx.attr, "friend", None) + if bool(friend): + if bool(friends): + fail("Can only use friend or friends, but not both. Please only set `friend=`") + friends = [friend] + if len(friends) == 0: return struct( targets = [], module_name = _utils.derive_module_name(ctx), - paths = [], + paths = depset(), ) elif len(friends) == 1: + print("Found friend: %s" % friends[0]) if friends[0][_KtJvmInfo] == None: fail("only kotlin dependencies can be friends") elif ctx.attr.module_name: fail("if friends has been set then module_name cannot be provided") else: + toolchains = _compiler_toolchains(ctx) + paths = depset( + direct = [x.class_jar.path for x in friends[0][JavaInfo].outputs.jars], + transitive = [friends[0][_KtJvmInfo].friend_paths], + ) + print("Friend paths: %s" % paths) return struct( targets = friends, - paths = friends[0][JavaInfo].compile_jars, + paths = paths, module_name = friends[0][_KtJvmInfo].module_name, ) else: - fail("only one friend is possible") + fail("Only one friend is presently supported.") def _compiler_deps(toolchains, friend, deps): """Encapsulates compiler dependency metadata.""" @@ -260,6 +273,7 @@ def kt_jvm_compile_action(ctx, rule_kind, output_jar): kt = _KtJvmInfo( srcs = ctx.files.srcs, module_name = friend.module_name, + friend_paths = friend.paths, language_version = toolchains.kt.api_version, # intellij aspect needs this. outputs = struct( diff --git a/kotlin/internal/jvm/jvm.bzl b/kotlin/internal/jvm/jvm.bzl index 19eb05c06..d596425dc 100644 --- a/kotlin/internal/jvm/jvm.bzl +++ b/kotlin/internal/jvm/jvm.bzl @@ -163,6 +163,19 @@ _common_attr = utils.add_dicts( default = [], allow_files = False, ), + "friend": attr.label( + doc = """A single Kotlin dep which allows this code to access internal members of the given dependency. + Currently uses the output jar of the module -- i.e., exported deps won't be included. + + DEPRECATED - PLEASE USE `friend=` instead.""", + providers = [JavaInfo, _KtJvmInfo], + ), + "friends": attr.label_list( + doc = """A single Kotlin dep which allows this code to access internal members of the given dependency. + Currently uses the output jar of the module -- i.e., exported deps won't be included.""", + default = [], + providers = [JavaInfo, _KtJvmInfo], + ), "resources": attr.label_list( doc = """A list of files that should be include in a Java jar.""", default = [], @@ -270,12 +283,6 @@ kt_jvm_test = rule( default = Label("@bazel_tools//tools/jdk:TestRunner_deploy.jar"), allow_files = True, ), - "friends": attr.label_list( - doc = """A single Kotlin dep which allows the test code access to internal members. Currently uses the output - jar of the module -- i.e., exported deps won't be included.""", - default = [], - providers = [JavaInfo, _KtJvmInfo], - ), "test_class": attr.string( doc = "The Java class to be loaded by the test runner.", default = "",