diff --git a/docs/kotlin.md b/docs/kotlin.md index 827f240c3..3bca74dc1 100644 --- a/docs/kotlin.md +++ b/docs/kotlin.md @@ -525,6 +525,7 @@ load("@rules_kotlin//kotlin:core.bzl", "define_kt_toolchain") define_kt_toolchain(name, language_version, api_version, jvm_target, experimental_use_abi_jars, experimental_treat_internal_as_private_in_abi_jars, experimental_remove_private_classes_in_abi_jars, + experimental_generate_associates_abi_jars, experimental_remove_debug_info_in_abi_jars, experimental_strict_kotlin_deps, experimental_report_unused_deps, experimental_reduce_classpath_mode, experimental_multiplex_workers, experimental_build_tools_api, javac_options, @@ -546,6 +547,7 @@ Define the Kotlin toolchain. | experimental_use_abi_jars |
-
| `False` | | experimental_treat_internal_as_private_in_abi_jars |-
| `False` | | experimental_remove_private_classes_in_abi_jars |-
| `False` | +| experimental_generate_associates_abi_jars |-
| `False` | | experimental_remove_debug_info_in_abi_jars |-
| `False` | | experimental_strict_kotlin_deps |-
| `None` | | experimental_report_unused_deps |-
| `None` | diff --git a/examples/associates_dagger/.bazelrc b/examples/associates_dagger/.bazelrc new file mode 100644 index 000000000..ce4930041 --- /dev/null +++ b/examples/associates_dagger/.bazelrc @@ -0,0 +1,2 @@ +common --java_runtime_version=remotejdk_21 +common --tool_java_runtime_version=remotejdk_21 diff --git a/examples/associates_dagger/.bazelversion b/examples/associates_dagger/.bazelversion new file mode 120000 index 000000000..96cf94962 --- /dev/null +++ b/examples/associates_dagger/.bazelversion @@ -0,0 +1 @@ +../../.bazelversion \ No newline at end of file diff --git a/examples/associates_dagger/BUILD b/examples/associates_dagger/BUILD new file mode 100644 index 000000000..538ad1b23 --- /dev/null +++ b/examples/associates_dagger/BUILD @@ -0,0 +1,11 @@ +load("@rules_kotlin//kotlin:core.bzl", "define_kt_toolchain") + +define_kt_toolchain( + name = "kotlin_toolchain", + api_version = "2.1", + experimental_generate_associates_abi_jars = True, + experimental_remove_private_classes_in_abi_jars = True, + experimental_treat_internal_as_private_in_abi_jars = True, + experimental_use_abi_jars = True, + language_version = "2.1", +) diff --git a/examples/associates_dagger/MODULE.bazel b/examples/associates_dagger/MODULE.bazel new file mode 100644 index 000000000..b09d32933 --- /dev/null +++ b/examples/associates_dagger/MODULE.bazel @@ -0,0 +1,29 @@ +module(name = "associates-dagger-example") + +bazel_dep(name = "bazel_skylib", version = "1.7.1") +bazel_dep(name = "rules_java", version = "8.9.0") +bazel_dep(name = "rules_kotlin", version = "2.2.0") +local_path_override( + module_name = "rules_kotlin", + path = "../..", +) + +register_toolchains("//:kotlin_toolchain") + +bazel_dep(name = "rules_jvm_external", version = "6.10") + +maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") +maven.install( + name = "maven_rules_kotlin_example", + artifacts = [ + "com.google.dagger:dagger:2.59", + "com.google.dagger:dagger-compiler:2.59", + "com.google.dagger:dagger-producers:2.59", + "javax.inject:javax.inject:1", + ], + lock_file = "//:maven_install.json", + repositories = [ + "https://repo1.maven.org/maven2", + ], +) +use_repo(maven, "maven_rules_kotlin_example") diff --git a/examples/associates_dagger/WORKSPACE b/examples/associates_dagger/WORKSPACE new file mode 100644 index 000000000..e86bb038a --- /dev/null +++ b/examples/associates_dagger/WORKSPACE @@ -0,0 +1,120 @@ +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "rules_kotlin", + sha256 = "34e8c0351764b71d78f76c8746e98063979ce08dcf1a91666f3f3bc2949a533d", + url = "https://github.com/bazelbuild/rules_kotlin/releases/download/v1.9.5/rules_kotlin-v1.9.5.tar.gz", +) + +load("@rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories", "versions") + +http_archive( + name = "rules_jvm_external", + sha256 = versions.RULES_JVM_EXTERNAL.sha256, + strip_prefix = "rules_jvm_external-%s" % versions.RULES_JVM_EXTERNAL.version, + urls = [url.format(version = versions.RULES_JVM_EXTERNAL.version) for url in versions.RULES_JVM_EXTERNAL.url_templates], +) + +http_archive( + name = "rules_android", + sha256 = versions.RULES_ANDROID.sha256, + strip_prefix = versions.RULES_ANDROID.strip_prefix_template.format(version = versions.RULES_ANDROID.version), + urls = [url.format(version = versions.RULES_ANDROID.version) for url in versions.RULES_ANDROID.url_templates], +) + +http_archive( + name = "rules_shell", + sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043", + strip_prefix = "rules_shell-0.4.0", + url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz", +) + +http_archive( + name = "bazel_skylib", + sha256 = versions.BAZEL_SKYLIB.sha256, + urls = [url.format(version = versions.BAZEL_SKYLIB.version) for url in versions.BAZEL_SKYLIB.url_templates], +) + +http_archive( + name = "bazel_features", + sha256 = versions.BAZEL_FEATURES.sha256, + strip_prefix = versions.BAZEL_FEATURES.strip_prefix_template.format(version = versions.BAZEL_FEATURES.version), + urls = [url.format(version = versions.BAZEL_FEATURES.version) for url in versions.BAZEL_FEATURES.url_templates], +) + +load("@bazel_features//:deps.bzl", "bazel_features_deps") + +bazel_features_deps() + +http_archive( + name = "bazel_lib", + sha256 = versions.BAZEL_LIB.sha256, + strip_prefix = versions.BAZEL_LIB.strip_prefix_template.format(version = versions.BAZEL_LIB.version), + urls = [url.format(version = versions.BAZEL_LIB.version) for url in versions.BAZEL_LIB.url_templates], +) + +http_archive( + name = "rules_cc", + sha256 = versions.RULES_CC.sha256, + strip_prefix = versions.RULES_CC.strip_prefix_template.format(version = versions.RULES_CC.version), + urls = [url.format(version = versions.RULES_CC.version) for url in versions.RULES_CC.url_templates], +) + +load("@rules_cc//cc:repositories.bzl", "rules_cc_dependencies", "rules_cc_toolchains") + +rules_cc_dependencies() + +rules_cc_toolchains() + +http_archive( + name = "rules_java", + sha256 = versions.RULES_JAVA.sha256, + urls = [url.format(version = versions.RULES_JAVA.version) for url in versions.RULES_JAVA.url_templates], +) + +kotlin_repositories() + +load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies") + +rules_java_dependencies() + +load("@com_google_protobuf//bazel/private:proto_bazel_features.bzl", "proto_bazel_features") # buildifier: disable=bzl-visibility + +proto_bazel_features(name = "proto_bazel_features") + +load("@rules_java//java:repositories.bzl", "rules_java_toolchains") + +rules_java_toolchains() + +load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps") + +rules_jvm_external_deps() + +load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup") + +rules_jvm_external_setup() + +load("@rules_kotlin//kotlin:core.bzl", "kt_register_toolchains") + +kt_register_toolchains() + +load("@rules_shell//shell:repositories.bzl", "rules_shell_dependencies", "rules_shell_toolchains") + +rules_shell_dependencies() + +rules_shell_toolchains() + +load("@rules_jvm_external//:defs.bzl", "maven_install") + +maven_install( + name = "maven_rules_kotlin_example", + artifacts = [ + "com.google.dagger:dagger:2.57.2", + "com.google.dagger:dagger-compiler:2.57.2", + "com.google.dagger:dagger-producers:2.57.2", + "javax.inject:javax.inject:1", + ], + repositories = [ + "https://repo1.maven.org/maven2", + ], +) diff --git a/examples/associates_dagger/maven_install.json b/examples/associates_dagger/maven_install.json new file mode 100644 index 000000000..2e37cde33 --- /dev/null +++ b/examples/associates_dagger/maven_install.json @@ -0,0 +1,629 @@ +{ + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": { + "com.google.dagger:dagger": 232202338, + "com.google.dagger:dagger-compiler": -362498016, + "com.google.dagger:dagger-producers": -1075076722, + "javax.inject:javax.inject": -297932879, + "repositories": -1949687017 + }, + "__RESOLVED_ARTIFACTS_HASH": { + "com.google.code.findbugs:jsr305": 870839855, + "com.google.dagger:dagger": 1575529838, + "com.google.dagger:dagger-compiler": -49134844, + "com.google.dagger:dagger-producers": 1726420995, + "com.google.dagger:dagger-spi": 630982554, + "com.google.devtools.ksp:symbol-processing-api": -732428888, + "com.google.errorprone:error_prone_annotations": 712292353, + "com.google.googlejavaformat:google-java-format": -2085760752, + "com.google.guava:failureaccess": -718864417, + "com.google.guava:guava": -1058030103, + "com.google.guava:listenablefuture": 1079558157, + "com.google.j2objc:j2objc-annotations": 248818742, + "com.squareup:javapoet": -2135371934, + "com.squareup:kotlinpoet": -303024748, + "jakarta.inject:jakarta.inject-api": 188991469, + "javax.inject:javax.inject": 698155243, + "net.ltgt.gradle.incap:incap": 641640589, + "org.checkerframework:checker-compat-qual": -1467964223, + "org.checkerframework:checker-qual": 628949150, + "org.jetbrains.kotlin:kotlin-metadata-jvm": 2058544870, + "org.jetbrains.kotlin:kotlin-reflect": -1488851255, + "org.jetbrains.kotlin:kotlin-stdlib": 689270517, + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": -235243283, + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": -566798102, + "org.jetbrains:annotations": 554168982, + "org.jspecify:jspecify": 117231129 + }, + "artifacts": { + "com.google.code.findbugs:jsr305": { + "shasums": { + "jar": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" + }, + "version": "3.0.2" + }, + "com.google.dagger:dagger": { + "shasums": { + "jar": "94d5b23812cc12fa903c9ac4a42978e7e7b2622e6b51c17f8b12037ceece43cd" + }, + "version": "2.59" + }, + "com.google.dagger:dagger-compiler": { + "shasums": { + "jar": "6a0a2ec75e775ff8cdcd84c8b0bfa975730bf000c24d6178f1662a27b94a098e" + }, + "version": "2.59" + }, + "com.google.dagger:dagger-producers": { + "shasums": { + "jar": "7417ab1a9fbd28cdeec15070c18769706d8554451099cee88ded2f584e8460f0" + }, + "version": "2.59" + }, + "com.google.dagger:dagger-spi": { + "shasums": { + "jar": "e89d1a2c0a55d4238a05a8dedd9e33c4eb87f26d0dcf29164edf10e857ff9edf" + }, + "version": "2.59" + }, + "com.google.devtools.ksp:symbol-processing-api": { + "shasums": { + "jar": "a20644569ecc01467d3efe4f8b9787a8719ce27ed12b6a3475ae1d82bfb16a0e" + }, + "version": "2.2.20-2.0.3" + }, + "com.google.errorprone:error_prone_annotations": { + "shasums": { + "jar": "6ba61510e22944e8aec3fe970972d088d8da132a24f2bc817a43c7b70665cc2b" + }, + "version": "2.45.0" + }, + "com.google.googlejavaformat:google-java-format": { + "shasums": { + "jar": "1265aa761ec2908535324b114995a1c6debaedc8a9e2e8553127babcdb58567f" + }, + "version": "1.33.0" + }, + "com.google.guava:failureaccess": { + "shasums": { + "jar": "8a8f81cf9b359e3f6dfa691a1e776985c061ef2f223c9b2c80753e1b458e8064" + }, + "version": "1.0.2" + }, + "com.google.guava:guava": { + "shasums": { + "jar": "f4d85c3e4d411694337cb873abea09b242b664bb013320be6105327c45991537" + }, + "version": "33.0.0-jre" + }, + "com.google.guava:listenablefuture": { + "shasums": { + "jar": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" + }, + "version": "9999.0-empty-to-avoid-conflict-with-guava" + }, + "com.google.j2objc:j2objc-annotations": { + "shasums": { + "jar": "f02a95fa1a5e95edb3ed859fd0fb7df709d121a35290eff8b74dce2ab7f4d6ed" + }, + "version": "2.8" + }, + "com.squareup:javapoet": { + "shasums": { + "jar": "4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291" + }, + "version": "1.13.0" + }, + "com.squareup:kotlinpoet": { + "shasums": { + "jar": "2887ada1ca03dd83baa2758640d87e840d1907564db0ef88d2289c868a980492" + }, + "version": "1.11.0" + }, + "jakarta.inject:jakarta.inject-api": { + "shasums": { + "jar": "f7dc98062fccf14126abb751b64fab12c312566e8cbdc8483598bffcea93af7c" + }, + "version": "2.0.1" + }, + "javax.inject:javax.inject": { + "shasums": { + "jar": "91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff" + }, + "version": "1" + }, + "net.ltgt.gradle.incap:incap": { + "shasums": { + "jar": "b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd" + }, + "version": "0.2" + }, + "org.checkerframework:checker-compat-qual": { + "shasums": { + "jar": "d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d" + }, + "version": "2.5.3" + }, + "org.checkerframework:checker-qual": { + "shasums": { + "jar": "2f9f245bf68e4259d610894f2406dc1f6363dc639302bd566e8272e4f4541172" + }, + "version": "3.41.0" + }, + "org.jetbrains.kotlin:kotlin-metadata-jvm": { + "shasums": { + "jar": "8524eac90f7e8e0f1366883f2c6c820c93bfa61df3d76857c8d3e803cf67315d" + }, + "version": "2.2.20" + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "shasums": { + "jar": "3277ac102ae17aad10a55abec75ff5696c8d109790396434b496e75087854203" + }, + "version": "1.6.10" + }, + "org.jetbrains.kotlin:kotlin-stdlib": { + "shasums": { + "jar": "8836ccffd3585fadda9901244b20d42901d2f3cd581058d8434e2ffabcf3a3e7" + }, + "version": "2.2.20" + }, + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": { + "shasums": { + "jar": "2aedcdc6b69b33bdf5cc235bcea88e7cf6601146bb6bcdffdb312bbacd7be261" + }, + "version": "1.6.10" + }, + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": { + "shasums": { + "jar": "1456d82d039ea30d8485b032901f52bbf07e7cdbe8bb1f8708ad32a8574c41ce" + }, + "version": "1.6.10" + }, + "org.jetbrains:annotations": { + "shasums": { + "jar": "ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478" + }, + "version": "13.0" + }, + "org.jspecify:jspecify": { + "shasums": { + "jar": "1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab" + }, + "version": "1.0.0" + } + }, + "dependencies": { + "com.google.dagger:dagger": [ + "jakarta.inject:jakarta.inject-api", + "javax.inject:javax.inject", + "org.jspecify:jspecify" + ], + "com.google.dagger:dagger-compiler": [ + "com.google.code.findbugs:jsr305", + "com.google.dagger:dagger", + "com.google.dagger:dagger-spi", + "com.google.devtools.ksp:symbol-processing-api", + "com.google.googlejavaformat:google-java-format", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.squareup:javapoet", + "com.squareup:kotlinpoet", + "javax.inject:javax.inject", + "net.ltgt.gradle.incap:incap", + "org.checkerframework:checker-compat-qual", + "org.jetbrains.kotlin:kotlin-metadata-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.google.dagger:dagger-producers": [ + "com.google.dagger:dagger", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "javax.inject:javax.inject", + "org.checkerframework:checker-compat-qual" + ], + "com.google.dagger:dagger-spi": [ + "com.google.code.findbugs:jsr305", + "com.google.dagger:dagger", + "com.google.devtools.ksp:symbol-processing-api", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.squareup:javapoet", + "javax.inject:javax.inject" + ], + "com.google.devtools.ksp:symbol-processing-api": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.google.googlejavaformat:google-java-format": [ + "com.google.guava:guava" + ], + "com.google.guava:guava": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:failureaccess", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "org.checkerframework:checker-qual" + ], + "com.squareup:kotlinpoet": [ + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "org.jetbrains.kotlin:kotlin-metadata-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-reflect": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "org.jetbrains:annotations" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7" + ] + }, + "packages": { + "com.google.code.findbugs:jsr305": [ + "javax.annotation", + "javax.annotation.concurrent", + "javax.annotation.meta" + ], + "com.google.dagger:dagger": [ + "dagger", + "dagger.assisted", + "dagger.internal", + "dagger.multibindings" + ], + "com.google.dagger:dagger-compiler": [ + "dagger.internal.codegen", + "dagger.internal.codegen.base", + "dagger.internal.codegen.binding", + "dagger.internal.codegen.bindinggraphvalidation", + "dagger.internal.codegen.compileroption", + "dagger.internal.codegen.componentgenerator", + "dagger.internal.codegen.kotlin", + "dagger.internal.codegen.model", + "dagger.internal.codegen.processingstep", + "dagger.internal.codegen.validation", + "dagger.internal.codegen.writing", + "dagger.internal.codegen.xprocessing", + "dagger.spi.internal.shaded.androidx.room3.compiler.codegen", + "dagger.spi.internal.shaded.androidx.room3.compiler.codegen.compat", + "dagger.spi.internal.shaded.androidx.room3.compiler.codegen.impl", + "dagger.spi.internal.shaded.androidx.room3.compiler.codegen.java", + "dagger.spi.internal.shaded.androidx.room3.compiler.codegen.kotlin", + "dagger.spi.internal.shaded.androidx.room3.compiler.processing", + "dagger.spi.internal.shaded.androidx.room3.compiler.processing.compat", + "dagger.spi.internal.shaded.androidx.room3.compiler.processing.javac", + "dagger.spi.internal.shaded.androidx.room3.compiler.processing.javac.kotlin", + "dagger.spi.internal.shaded.androidx.room3.compiler.processing.ksp", + "dagger.spi.internal.shaded.androidx.room3.compiler.processing.ksp.synthetic", + "dagger.spi.internal.shaded.androidx.room3.compiler.processing.util" + ], + "com.google.dagger:dagger-producers": [ + "dagger.producers", + "dagger.producers.internal", + "dagger.producers.monitoring", + "dagger.producers.monitoring.internal" + ], + "com.google.dagger:dagger-spi": [ + "dagger.internal.codegen.extension", + "dagger.model", + "dagger.spi", + "dagger.spi.internal.shaded.com.google.auto.common", + "dagger.spi.internal.shaded.com.squareup.kotlinpoet.javapoet", + "dagger.spi.model" + ], + "com.google.devtools.ksp:symbol-processing-api": [ + "com.google.devtools.ksp", + "com.google.devtools.ksp.processing", + "com.google.devtools.ksp.symbol", + "com.google.devtools.ksp.visitor" + ], + "com.google.errorprone:error_prone_annotations": [ + "com.google.errorprone.annotations", + "com.google.errorprone.annotations.concurrent" + ], + "com.google.googlejavaformat:google-java-format": [ + "com.google.googlejavaformat", + "com.google.googlejavaformat.java", + "com.google.googlejavaformat.java.filer", + "com.google.googlejavaformat.java.javadoc" + ], + "com.google.guava:failureaccess": [ + "com.google.common.util.concurrent.internal" + ], + "com.google.guava:guava": [ + "com.google.common.annotations", + "com.google.common.base", + "com.google.common.base.internal", + "com.google.common.cache", + "com.google.common.collect", + "com.google.common.escape", + "com.google.common.eventbus", + "com.google.common.graph", + "com.google.common.hash", + "com.google.common.html", + "com.google.common.io", + "com.google.common.math", + "com.google.common.net", + "com.google.common.primitives", + "com.google.common.reflect", + "com.google.common.util.concurrent", + "com.google.common.xml", + "com.google.thirdparty.publicsuffix" + ], + "com.google.j2objc:j2objc-annotations": [ + "com.google.j2objc.annotations" + ], + "com.squareup:javapoet": [ + "com.squareup.javapoet" + ], + "com.squareup:kotlinpoet": [ + "com.squareup.kotlinpoet", + "com.squareup.kotlinpoet.jvm", + "com.squareup.kotlinpoet.tags" + ], + "jakarta.inject:jakarta.inject-api": [ + "jakarta.inject" + ], + "javax.inject:javax.inject": [ + "javax.inject" + ], + "net.ltgt.gradle.incap:incap": [ + "net.ltgt.gradle.incap" + ], + "org.checkerframework:checker-compat-qual": [ + "org.checkerframework.checker.nullness.compatqual" + ], + "org.checkerframework:checker-qual": [ + "org.checkerframework.checker.builder.qual", + "org.checkerframework.checker.calledmethods.qual", + "org.checkerframework.checker.compilermsgs.qual", + "org.checkerframework.checker.fenum.qual", + "org.checkerframework.checker.formatter.qual", + "org.checkerframework.checker.guieffect.qual", + "org.checkerframework.checker.i18n.qual", + "org.checkerframework.checker.i18nformatter.qual", + "org.checkerframework.checker.index.qual", + "org.checkerframework.checker.initialization.qual", + "org.checkerframework.checker.interning.qual", + "org.checkerframework.checker.lock.qual", + "org.checkerframework.checker.mustcall.qual", + "org.checkerframework.checker.nullness.qual", + "org.checkerframework.checker.optional.qual", + "org.checkerframework.checker.propkey.qual", + "org.checkerframework.checker.regex.qual", + "org.checkerframework.checker.signature.qual", + "org.checkerframework.checker.signedness.qual", + "org.checkerframework.checker.tainting.qual", + "org.checkerframework.checker.units.qual", + "org.checkerframework.common.aliasing.qual", + "org.checkerframework.common.initializedfields.qual", + "org.checkerframework.common.reflection.qual", + "org.checkerframework.common.returnsreceiver.qual", + "org.checkerframework.common.subtyping.qual", + "org.checkerframework.common.util.report.qual", + "org.checkerframework.common.value.qual", + "org.checkerframework.dataflow.qual", + "org.checkerframework.framework.qual" + ], + "org.jetbrains.kotlin:kotlin-metadata-jvm": [ + "kotlin.metadata", + "kotlin.metadata.internal", + "kotlin.metadata.internal.common", + "kotlin.metadata.internal.extensions", + "kotlin.metadata.internal.metadata", + "kotlin.metadata.internal.metadata.builtins", + "kotlin.metadata.internal.metadata.deserialization", + "kotlin.metadata.internal.metadata.jvm", + "kotlin.metadata.internal.metadata.jvm.deserialization", + "kotlin.metadata.internal.metadata.jvm.serialization", + "kotlin.metadata.internal.metadata.serialization", + "kotlin.metadata.internal.protobuf", + "kotlin.metadata.jvm", + "kotlin.metadata.jvm.internal" + ], + "org.jetbrains.kotlin:kotlin-reflect": [ + "kotlin.reflect.full", + "kotlin.reflect.jvm", + "kotlin.reflect.jvm.internal", + "kotlin.reflect.jvm.internal.calls", + "kotlin.reflect.jvm.internal.impl", + "kotlin.reflect.jvm.internal.impl.builtins", + "kotlin.reflect.jvm.internal.impl.builtins.functions", + "kotlin.reflect.jvm.internal.impl.builtins.jvm", + "kotlin.reflect.jvm.internal.impl.descriptors", + "kotlin.reflect.jvm.internal.impl.descriptors.annotations", + "kotlin.reflect.jvm.internal.impl.descriptors.deserialization", + "kotlin.reflect.jvm.internal.impl.descriptors.impl", + "kotlin.reflect.jvm.internal.impl.descriptors.java", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.components", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.structure", + "kotlin.reflect.jvm.internal.impl.incremental", + "kotlin.reflect.jvm.internal.impl.incremental.components", + "kotlin.reflect.jvm.internal.impl.load.java", + "kotlin.reflect.jvm.internal.impl.load.java.components", + "kotlin.reflect.jvm.internal.impl.load.java.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.types", + "kotlin.reflect.jvm.internal.impl.load.java.sources", + "kotlin.reflect.jvm.internal.impl.load.java.structure", + "kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement", + "kotlin.reflect.jvm.internal.impl.load.kotlin", + "kotlin.reflect.jvm.internal.impl.load.kotlin.header", + "kotlin.reflect.jvm.internal.impl.metadata", + "kotlin.reflect.jvm.internal.impl.metadata.builtins", + "kotlin.reflect.jvm.internal.impl.metadata.deserialization", + "kotlin.reflect.jvm.internal.impl.metadata.jvm", + "kotlin.reflect.jvm.internal.impl.metadata.jvm.deserialization", + "kotlin.reflect.jvm.internal.impl.name", + "kotlin.reflect.jvm.internal.impl.platform", + "kotlin.reflect.jvm.internal.impl.protobuf", + "kotlin.reflect.jvm.internal.impl.renderer", + "kotlin.reflect.jvm.internal.impl.resolve", + "kotlin.reflect.jvm.internal.impl.resolve.calls.inference", + "kotlin.reflect.jvm.internal.impl.resolve.constants", + "kotlin.reflect.jvm.internal.impl.resolve.deprecation", + "kotlin.reflect.jvm.internal.impl.resolve.descriptorUtil", + "kotlin.reflect.jvm.internal.impl.resolve.jvm", + "kotlin.reflect.jvm.internal.impl.resolve.sam", + "kotlin.reflect.jvm.internal.impl.resolve.scopes", + "kotlin.reflect.jvm.internal.impl.resolve.scopes.receivers", + "kotlin.reflect.jvm.internal.impl.serialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors", + "kotlin.reflect.jvm.internal.impl.storage", + "kotlin.reflect.jvm.internal.impl.types", + "kotlin.reflect.jvm.internal.impl.types.checker", + "kotlin.reflect.jvm.internal.impl.types.error", + "kotlin.reflect.jvm.internal.impl.types.model", + "kotlin.reflect.jvm.internal.impl.types.typeUtil", + "kotlin.reflect.jvm.internal.impl.types.typesApproximation", + "kotlin.reflect.jvm.internal.impl.util", + "kotlin.reflect.jvm.internal.impl.util.capitalizeDecapitalize", + "kotlin.reflect.jvm.internal.impl.util.collectionUtils", + "kotlin.reflect.jvm.internal.impl.utils", + "kotlin.reflect.jvm.internal.pcollections" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "kotlin", + "kotlin.annotation", + "kotlin.collections", + "kotlin.collections.builders", + "kotlin.collections.jdk8", + "kotlin.collections.unsigned", + "kotlin.comparisons", + "kotlin.concurrent", + "kotlin.concurrent.atomics", + "kotlin.concurrent.internal", + "kotlin.contracts", + "kotlin.coroutines", + "kotlin.coroutines.cancellation", + "kotlin.coroutines.intrinsics", + "kotlin.coroutines.jvm.internal", + "kotlin.enums", + "kotlin.experimental", + "kotlin.internal", + "kotlin.internal.jdk7", + "kotlin.internal.jdk8", + "kotlin.io", + "kotlin.io.encoding", + "kotlin.io.path", + "kotlin.jdk7", + "kotlin.js", + "kotlin.jvm", + "kotlin.jvm.functions", + "kotlin.jvm.internal", + "kotlin.jvm.internal.markers", + "kotlin.jvm.internal.unsafe", + "kotlin.jvm.jdk8", + "kotlin.jvm.optionals", + "kotlin.math", + "kotlin.properties", + "kotlin.random", + "kotlin.random.jdk8", + "kotlin.ranges", + "kotlin.reflect", + "kotlin.sequences", + "kotlin.streams.jdk8", + "kotlin.system", + "kotlin.text", + "kotlin.text.jdk8", + "kotlin.time", + "kotlin.time.jdk8", + "kotlin.uuid" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": [ + "kotlin.internal.jdk7", + "kotlin.io.path", + "kotlin.jdk7" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": [ + "kotlin.collections.jdk8", + "kotlin.internal.jdk8", + "kotlin.jvm.jdk8", + "kotlin.random.jdk8", + "kotlin.streams.jdk8", + "kotlin.text.jdk8", + "kotlin.time.jdk8" + ], + "org.jetbrains:annotations": [ + "org.intellij.lang.annotations", + "org.jetbrains.annotations" + ], + "org.jspecify:jspecify": [ + "org.jspecify.annotations" + ] + }, + "repositories": { + "https://repo1.maven.org/maven2/": [ + "com.google.code.findbugs:jsr305", + "com.google.dagger:dagger", + "com.google.dagger:dagger-compiler", + "com.google.dagger:dagger-producers", + "com.google.dagger:dagger-spi", + "com.google.devtools.ksp:symbol-processing-api", + "com.google.errorprone:error_prone_annotations", + "com.google.googlejavaformat:google-java-format", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "com.squareup:javapoet", + "com.squareup:kotlinpoet", + "jakarta.inject:jakarta.inject-api", + "javax.inject:javax.inject", + "net.ltgt.gradle.incap:incap", + "org.checkerframework:checker-compat-qual", + "org.checkerframework:checker-qual", + "org.jetbrains.kotlin:kotlin-metadata-jvm", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains:annotations", + "org.jspecify:jspecify" + ] + }, + "services": { + "com.google.dagger:dagger-compiler": { + "com.google.devtools.ksp.processing.SymbolProcessorProvider": [ + "dagger.internal.codegen.KspComponentProcessor$Provider" + ], + "javax.annotation.processing.Processor": [ + "dagger.internal.codegen.ComponentProcessor" + ] + }, + "com.google.googlejavaformat:google-java-format": { + "java.util.spi.ToolProvider": [ + "com.google.googlejavaformat.java.GoogleJavaFormatToolProvider" + ], + "javax.tools.Tool": [ + "com.google.googlejavaformat.java.GoogleJavaFormatTool" + ] + }, + "org.jetbrains.kotlin:kotlin-metadata-jvm": { + "kotlin.metadata.internal.extensions.MetadataExtensions": [ + "kotlin.metadata.jvm.internal.JvmMetadataExtensions" + ] + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader": [ + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins.BuiltInsLoaderImpl" + ], + "kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition": [ + "kotlin.reflect.jvm.internal.impl.load.java.ErasedOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.FieldOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.JavaIncompatibilityRulesOverridabilityCondition" + ] + } + }, + "version": "3" +} diff --git a/examples/associates_dagger/projects/service/api/BUILD.bazel b/examples/associates_dagger/projects/service/api/BUILD.bazel new file mode 100644 index 000000000..b333e035a --- /dev/null +++ b/examples/associates_dagger/projects/service/api/BUILD.bazel @@ -0,0 +1,8 @@ +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") + +package(default_visibility = ["//projects/service:__subpackages__"]) + +kt_jvm_library( + name = "api", + srcs = glob(["src/main/kotlin/**/*.kt"]), +) diff --git a/examples/associates_dagger/projects/service/api/src/main/kotlin/service/api/Greeter.kt b/examples/associates_dagger/projects/service/api/src/main/kotlin/service/api/Greeter.kt new file mode 100644 index 000000000..236d9937b --- /dev/null +++ b/examples/associates_dagger/projects/service/api/src/main/kotlin/service/api/Greeter.kt @@ -0,0 +1,5 @@ +package service.api + +interface Greeter { + fun greet(): String +} diff --git a/examples/associates_dagger/projects/service/api/src/main/kotlin/service/api/Logger.kt b/examples/associates_dagger/projects/service/api/src/main/kotlin/service/api/Logger.kt new file mode 100644 index 000000000..3c3b99abd --- /dev/null +++ b/examples/associates_dagger/projects/service/api/src/main/kotlin/service/api/Logger.kt @@ -0,0 +1,5 @@ +package service.api + +interface Logger { + fun log(message: String) +} diff --git a/examples/associates_dagger/projects/service/app/BUILD.bazel b/examples/associates_dagger/projects/service/app/BUILD.bazel new file mode 100644 index 000000000..fc59904a6 --- /dev/null +++ b/examples/associates_dagger/projects/service/app/BUILD.bazel @@ -0,0 +1,18 @@ +load("@rules_java//java:defs.bzl", "java_binary") +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") + +kt_jvm_library( + name = "app", + srcs = glob(["src/main/kotlin/**/*.kt"]), + deps = [ + "//projects/service/api", + "//projects/service/di", + ], +) + +java_binary( + name = "service", + main_class = "service.app.MainKt", + visibility = ["//visibility:public"], + runtime_deps = [":app"], +) diff --git a/examples/associates_dagger/projects/service/app/src/main/kotlin/service/app/Main.kt b/examples/associates_dagger/projects/service/app/src/main/kotlin/service/app/Main.kt new file mode 100644 index 000000000..e9caf48fb --- /dev/null +++ b/examples/associates_dagger/projects/service/app/src/main/kotlin/service/app/Main.kt @@ -0,0 +1,9 @@ +package service.app + +import service.di.DaggerServiceComponent + +fun main() { + val component = DaggerServiceComponent.builder().build() + val greeting = component.greeter().greet() + println(greeting) +} diff --git a/examples/associates_dagger/projects/service/di/BUILD.bazel b/examples/associates_dagger/projects/service/di/BUILD.bazel new file mode 100644 index 000000000..3dfa715fa --- /dev/null +++ b/examples/associates_dagger/projects/service/di/BUILD.bazel @@ -0,0 +1,13 @@ +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") + +kt_jvm_library( + name = "di", + srcs = glob(["src/main/kotlin/**/*.kt"]), + associates = [ + "//projects/service/impl", + ], + visibility = ["//projects/service:__subpackages__"], + deps = [ + "//third_party:dagger", + ], +) diff --git a/examples/associates_dagger/projects/service/di/src/main/kotlin/service/di/ServiceComponent.kt b/examples/associates_dagger/projects/service/di/src/main/kotlin/service/di/ServiceComponent.kt new file mode 100644 index 000000000..a0bb941c1 --- /dev/null +++ b/examples/associates_dagger/projects/service/di/src/main/kotlin/service/di/ServiceComponent.kt @@ -0,0 +1,11 @@ +package service.di + +import dagger.Component +import service.api.Greeter +import javax.inject.Singleton + +@Singleton +@Component(modules = [ServiceModule::class]) +interface ServiceComponent { + fun greeter(): Greeter +} diff --git a/examples/associates_dagger/projects/service/di/src/main/kotlin/service/di/ServiceModule.kt b/examples/associates_dagger/projects/service/di/src/main/kotlin/service/di/ServiceModule.kt new file mode 100644 index 000000000..89e0ac956 --- /dev/null +++ b/examples/associates_dagger/projects/service/di/src/main/kotlin/service/di/ServiceModule.kt @@ -0,0 +1,20 @@ +package service.di + +import dagger.Binds +import dagger.Module +import service.api.Greeter +import service.api.Logger +import service.impl.ConsoleLogger +import service.impl.DefaultGreeter +import javax.inject.Singleton + +@Module +internal abstract class ServiceModule { + @Binds + @Singleton + abstract fun bindLogger(impl: ConsoleLogger): Logger + + @Binds + @Singleton + abstract fun bindGreeter(impl: DefaultGreeter): Greeter +} diff --git a/examples/associates_dagger/projects/service/impl/BUILD.bazel b/examples/associates_dagger/projects/service/impl/BUILD.bazel new file mode 100644 index 000000000..374c2f588 --- /dev/null +++ b/examples/associates_dagger/projects/service/impl/BUILD.bazel @@ -0,0 +1,11 @@ +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") + +kt_jvm_library( + name = "impl", + srcs = glob(["src/main/kotlin/**/*.kt"]), + associates = ["//projects/service/api"], + visibility = ["//projects/service:__subpackages__"], + deps = [ + "@maven_rules_kotlin_example//:javax_inject_javax_inject", + ], +) diff --git a/examples/associates_dagger/projects/service/impl/src/main/kotlin/service/impl/ConsoleLogger.kt b/examples/associates_dagger/projects/service/impl/src/main/kotlin/service/impl/ConsoleLogger.kt new file mode 100644 index 000000000..186a4e436 --- /dev/null +++ b/examples/associates_dagger/projects/service/impl/src/main/kotlin/service/impl/ConsoleLogger.kt @@ -0,0 +1,10 @@ +package service.impl + +import service.api.Logger +import javax.inject.Inject + +internal class ConsoleLogger @Inject constructor() : Logger { + override fun log(message: String) { + println("[LOG] $message") + } +} diff --git a/examples/associates_dagger/projects/service/impl/src/main/kotlin/service/impl/DefaultGreeter.kt b/examples/associates_dagger/projects/service/impl/src/main/kotlin/service/impl/DefaultGreeter.kt new file mode 100644 index 000000000..ee9737990 --- /dev/null +++ b/examples/associates_dagger/projects/service/impl/src/main/kotlin/service/impl/DefaultGreeter.kt @@ -0,0 +1,15 @@ +package service.impl + +import service.api.Greeter +import service.api.Logger +import javax.inject.Inject + +internal class DefaultGreeter @Inject constructor( + private val logger: Logger, +) : Greeter { + override fun greet(): String { + val message = "Hello from DefaultGreeter!" + logger.log(message) + return message + } +} diff --git a/examples/associates_dagger/third_party/BUILD.bazel b/examples/associates_dagger/third_party/BUILD.bazel new file mode 100644 index 000000000..785b50aaf --- /dev/null +++ b/examples/associates_dagger/third_party/BUILD.bazel @@ -0,0 +1,22 @@ +load("@rules_java//java:java_library.bzl", "java_library") +load("@rules_java//java:java_plugin.bzl", "java_plugin") + +java_plugin( + name = "dagger_component_plugin", + generates_api = True, + processor_class = "dagger.internal.codegen.ComponentProcessor", + visibility = ["//visibility:private"], + deps = [ + "@maven_rules_kotlin_example//:com_google_dagger_dagger_compiler", + ], +) + +java_library( + name = "dagger", + exported_plugins = [":dagger_component_plugin"], + visibility = ["//visibility:public"], + exports = [ + "@maven_rules_kotlin_example//:com_google_dagger_dagger", + "@maven_rules_kotlin_example//:javax_inject_javax_inject", + ], +) diff --git a/kotlin/internal/jvm/associates.bzl b/kotlin/internal/jvm/associates.bzl index 71f1c7f0d..57a20907f 100644 --- a/kotlin/internal/jvm/associates.bzl +++ b/kotlin/internal/jvm/associates.bzl @@ -29,19 +29,27 @@ def _collect_associates(ctx, toolchains, associate): """Collects the associate jars from the provided dependency and returns them as a depset. - There are three outcomes for this marco: - 1. When `experimental_remove_private_classes_in_abi_jars` is enabled and the tag override has not been provided, only the + There are four outcomes for this macro: + 1. When the associate provides an associates_abi_jar (generated by ExperimentalAssociatesAbiGen plugin), + that jar is used directly. It contains ABI classes with internal visibility preserved. + 2. When `experimental_remove_private_classes_in_abi_jars` is enabled and the tag override has not been provided, only the direct java_output CLASS jars will be collected for each associate target. Due to the stripping of internal and private symbols from the compile jar, class jar is the only one that will contain the internal symbols an associate has access to. - 2. When `experimental_strict_associate_dependencies` is enabled and the tag override has not been provided, only the + 3. When `experimental_strict_associate_dependencies` is enabled and the tag override has not been provided, only the direct java_output COMPILE jars will be collected for each associate target. - 3. When `experimental_strict_associate_dependencies` is disabled, the complete transitive set of compile jars will - be collected for each assoicate target. + 4. When `experimental_strict_associate_dependencies` is disabled, the complete transitive set of compile jars will + be collected for each associate target. """ jars_depset = None abi_jars_set = _sets.make() - if (not "kt_remove_private_classes_in_abi_plugin_incompatible" in ctx.attr.tags and - toolchains.kt.experimental_remove_private_classes_in_abi_jars): + + # Prefer the associates ABI jar when available — it's an ABI jar that preserves internal visibility + associates_abi_jar = associate[_KtJvmInfo].associates_abi_jar if _KtJvmInfo in associate and hasattr(associate[_KtJvmInfo], "associates_abi_jar") else None + if associates_abi_jar: + jars_depset = depset(direct = [associates_abi_jar]) + abi_jars_set = _sets.union(abi_jars_set, _sets.make([a.compile_jar for a in associate[JavaInfo].java_outputs])) + elif (not "kt_remove_private_classes_in_abi_plugin_incompatible" in ctx.attr.tags and + toolchains.kt.experimental_remove_private_classes_in_abi_jars): jars_depset = depset(direct = [a.class_jar for a in associate[JavaInfo].java_outputs]) abi_jars_set = _sets.union(abi_jars_set, _sets.make([a.compile_jar for a in associate[JavaInfo].java_outputs])) elif (toolchains.kt.experimental_strict_associate_dependencies and diff --git a/kotlin/internal/jvm/compile.bzl b/kotlin/internal/jvm/compile.bzl index b3182c2a6..cc39b3e90 100644 --- a/kotlin/internal/jvm/compile.bzl +++ b/kotlin/internal/jvm/compile.bzl @@ -767,6 +767,7 @@ def _kt_jvm_produce_output_jar_actions( output_jars = outputs_struct.output_jars generated_src_jars = outputs_struct.generated_src_jars annotation_processing = outputs_struct.annotation_processing + associates_abi_jar = outputs_struct.associates_abi_jar # If this rule has any resources declared setup a zipper action to turn them into a jar. if len(ctx.files.resources) + len(extra_resources) > 0: @@ -849,6 +850,7 @@ def _kt_jvm_produce_output_jar_actions( annotation_processing = annotation_processing, additional_generated_source_jars = generated_src_jars, all_output_jars = output_jars, + associates_abi_jar = associates_abi_jar, ), ) @@ -919,6 +921,7 @@ def _run_kt_java_builder_actions( java_infos = [] # Build Kotlin + kt_associates_abi_jar = None if has_kt_sources: kt_runtime_jar = ctx.actions.declare_file(ctx.label.name + "-kt.jar") if not "kt_abi_plugin_incompatible" in ctx.attr.tags and toolchains.kt.experimental_use_abi_jars == True: @@ -927,6 +930,11 @@ def _run_kt_java_builder_actions( "abi_jar": kt_compile_jar, "output": kt_runtime_jar, } + + # Produce associates ABI jar (preserves internal visibility) alongside the regular ABI jar + if not "kt_associates_abi_plugin_incompatible" in ctx.attr.tags and toolchains.kt.experimental_generate_associates_abi_jars == True: + kt_associates_abi_jar = ctx.actions.declare_file(ctx.label.name + "-kt.associates-abi.jar") + outputs["associates_abi_jar"] = kt_associates_abi_jar else: kt_compile_jar = kt_runtime_jar outputs = { @@ -987,12 +995,19 @@ def _run_kt_java_builder_actions( # annotation processors in `deps` also. if len(srcs.kt) > 0: javac_opts.append("-proc:none") + + # Add associate ABI jars so javac (and annotation processors like Dagger) + # can resolve internal types from associated modules. + associates_java_infos = [ + JavaInfo(compile_jar = jar, output_jar = jar, neverlink = True) + for jar in compile_deps.associate_jars.to_list() + ] java_info = java_common.compile( ctx, source_files = srcs.java, source_jars = generated_kapt_src_jars + srcs.src_jars + generated_ksp_src_jars, output = ctx.actions.declare_file(ctx.label.name + "-java.jar"), - deps = compile_deps.deps + kt_stubs_for_java + [p[JavaInfo] for p in ctx.attr.plugins if JavaInfo in p], + deps = associates_java_infos + compile_deps.deps + kt_stubs_for_java + [p[JavaInfo] for p in ctx.attr.plugins if JavaInfo in p], java_toolchain = toolchains.java, plugins = _plugin_mappers.targets_to_annotation_processors_java_plugin_info(ctx.attr.plugins), javac_opts = javac_opts, @@ -1057,6 +1072,7 @@ def _run_kt_java_builder_actions( output_jars = output_jars, generated_src_jars = generated_kapt_src_jars + generated_ksp_src_jars, annotation_processing = annotation_processing, + associates_abi_jar = kt_associates_abi_jar, ) def _create_annotation_processing(annotation_processors, ap_class_jar, ap_source_jar): diff --git a/kotlin/internal/toolchains.bzl b/kotlin/internal/toolchains.bzl index bda1452ec..a2bc260e6 100644 --- a/kotlin/internal/toolchains.bzl +++ b/kotlin/internal/toolchains.bzl @@ -86,6 +86,7 @@ def _kotlin_toolchain_impl(ctx): experimental_use_abi_jars = ctx.attr.experimental_use_abi_jars, experimental_treat_internal_as_private_in_abi_jars = ctx.attr.experimental_treat_internal_as_private_in_abi_jars, experimental_remove_private_classes_in_abi_jars = ctx.attr.experimental_remove_private_classes_in_abi_jars, + experimental_generate_associates_abi_jars = ctx.attr.experimental_generate_associates_abi_jars, experimental_remove_debug_info_in_abi_jars = ctx.attr.experimental_remove_debug_info_in_abi_jars, experimental_strict_kotlin_deps = ctx.attr.experimental_strict_kotlin_deps, experimental_report_unused_deps = ctx.attr.experimental_report_unused_deps, @@ -138,6 +139,14 @@ _kt_toolchain = rule( doc = "Enables experimental support for Build Tools API integration", default = False, ), + "experimental_generate_associates_abi_jars": attr.bool( + doc = """Generate separate ABI jars for associates that preserve internal visibility. + When enabled, associate dependencies use these jars instead of full class jars, + improving build cache hit rates while maintaining access to internal symbols. + Can be disabled for an individual target using the tag. + `kt_associates_abi_plugin_incompatible`""", + default = False, + ), "experimental_multiplex_workers": attr.bool( doc = """Run workers in multiplex mode.""", default = False, @@ -349,6 +358,7 @@ def define_kt_toolchain( experimental_use_abi_jars = False, experimental_treat_internal_as_private_in_abi_jars = False, experimental_remove_private_classes_in_abi_jars = False, + experimental_generate_associates_abi_jars = False, experimental_remove_debug_info_in_abi_jars = False, experimental_strict_kotlin_deps = None, experimental_report_unused_deps = None, @@ -379,6 +389,7 @@ def define_kt_toolchain( }), experimental_treat_internal_as_private_in_abi_jars = experimental_treat_internal_as_private_in_abi_jars, experimental_remove_private_classes_in_abi_jars = experimental_remove_private_classes_in_abi_jars, + experimental_generate_associates_abi_jars = experimental_generate_associates_abi_jars, experimental_remove_debug_info_in_abi_jars = experimental_remove_debug_info_in_abi_jars, experimental_multiplex_workers = experimental_multiplex_workers, experimental_strict_kotlin_deps = experimental_strict_kotlin_deps, diff --git a/src/main/kotlin/BUILD b/src/main/kotlin/BUILD index d532ad4e4..8d03ffd06 100644 --- a/src/main/kotlin/BUILD +++ b/src/main/kotlin/BUILD @@ -20,6 +20,13 @@ jar_jar( visibility = ["//visibility:public"], ) +jar_jar( + name = "associates-abi-gen", + input_jar = "//src/main/kotlin/io/bazel/kotlin/plugin/associates:associates-abi-gen_deploy.jar", + rules = "shade.jarjar", + visibility = ["//visibility:public"], +) + alias( name = "build", actual = "//src/main/kotlin/io/bazel/kotlin/builder/cmd:build", @@ -47,6 +54,7 @@ alias( release_archive( name = "pkg", srcs = [ + ":associates-abi-gen.jar", ":jdeps-gen.jar", ":skip-code-gen.jar", ], diff --git a/src/main/kotlin/BUILD.release.bazel b/src/main/kotlin/BUILD.release.bazel index 00d75a9ca..bbad9a09d 100644 --- a/src/main/kotlin/BUILD.release.bazel +++ b/src/main/kotlin/BUILD.release.bazel @@ -46,9 +46,15 @@ java_import( jars = ["jdeps-gen.jar"], ) +java_import( + name = "associates-abi-gen", + jars = ["associates-abi-gen.jar"], +) + java_binary( name = "build", data = [ + ":associates-abi-gen", ":jdeps-gen", ":skip-code-gen", "//kotlin/compiler:jvm-abi-gen", @@ -70,6 +76,7 @@ java_binary( "-D@com_github_jetbrains_kotlin...jvm-abi-gen=$(rlocationpath //kotlin/compiler:jvm-abi-gen)", "-D@com_github_jetbrains_kotlin...kotlin-compiler=$(rlocationpath //kotlin/compiler:kotlin-compiler)", "-D@com_github_jetbrains_kotlin...kapt=$(rlocationpath //kotlin/compiler:kotlin-annotation-processing)", + "-D@rules_kotlin...associates-abi-gen=$(rlocationpath //src/main/kotlin:associates-abi-gen)", "-D@rules_kotlin...jdeps-gen=$(rlocationpath //src/main/kotlin:jdeps-gen)", "-D@rules_kotlin...skip-code-gen=$(rlocationpath //src/main/kotlin:skip-code-gen)", "-D@rules_kotlin...compiler=$(rlocationpath //src/main/kotlin/io/bazel/kotlin/compiler)", diff --git a/src/main/kotlin/io/bazel/kotlin/builder/cmd/BUILD.bazel b/src/main/kotlin/io/bazel/kotlin/builder/cmd/BUILD.bazel index f167ae561..3da95741f 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/cmd/BUILD.bazel +++ b/src/main/kotlin/io/bazel/kotlin/builder/cmd/BUILD.bazel @@ -18,6 +18,7 @@ kt_bootstrap_binary( "//kotlin/compiler:jvm-abi-gen", "//kotlin/compiler:kotlin-annotation-processing", "//kotlin/compiler:kotlin-compiler", + "//src/main/kotlin:associates-abi-gen", "//src/main/kotlin:jdeps-gen", "//src/main/kotlin:skip-code-gen", "//src/main/kotlin/io/bazel/kotlin/compiler:compiler.jar", @@ -36,6 +37,7 @@ kt_bootstrap_binary( "-D@com_github_jetbrains_kotlin...jvm-abi-gen=$(rlocationpath //kotlin/compiler:jvm-abi-gen)", "-D@com_github_jetbrains_kotlin...kotlin-compiler=$(rlocationpath //kotlin/compiler:kotlin-compiler)", "-D@com_github_jetbrains_kotlin...kapt=$(rlocationpath //kotlin/compiler:kotlin-annotation-processing)", + "-D@rules_kotlin...associates-abi-gen=$(rlocationpath //src/main/kotlin:associates-abi-gen)", "-D@rules_kotlin...jdeps-gen=$(rlocationpath //src/main/kotlin:jdeps-gen)", "-D@rules_kotlin...skip-code-gen=$(rlocationpath //src/main/kotlin:skip-code-gen)", "-D@rules_kotlin...compiler=$(rlocationpath //src/main/kotlin/io/bazel/kotlin/compiler:compiler.jar)", diff --git a/src/main/kotlin/io/bazel/kotlin/builder/cmd/Build.kt b/src/main/kotlin/io/bazel/kotlin/builder/cmd/Build.kt index ab20e8658..0d2754ef5 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/cmd/Build.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/cmd/Build.kt @@ -37,6 +37,7 @@ object Build { toolchain.skipCodeGen, toolchain.kapt3Plugin, toolchain.jdepsGen, + toolchain.associatesAbiGen, ) val compilerBuilder = KotlinToolchain.KotlincInvokerBuilder(toolchain) val jvmTaskExecutor = KotlinJvmTaskExecutor(compilerBuilder, plugins) 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 55d3e6e02..f46eba095 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt @@ -83,6 +83,7 @@ class KotlinBuilder( REDUCED_CLASSPATH_MODE("--reduced_classpath_mode"), INSTRUMENT_COVERAGE("--instrument_coverage"), BUILD_TOOLS_API("--build_tools_api"), + ASSOCIATES_ABI_JAR("--associates_abi_jar"), } } @@ -211,6 +212,7 @@ class KotlinBuilder( generatedJavaStubJar = this } argMap.optionalSingle(KotlinBuilderFlags.ABI_JAR)?.let { abijar = it } + argMap.optionalSingle(KotlinBuilderFlags.ASSOCIATES_ABI_JAR)?.let { associatesAbiJar = it } argMap.optionalSingle(KotlinBuilderFlags.GENERATED_CLASS_JAR)?.let { generatedClassJar = it } @@ -232,6 +234,13 @@ class KotlinBuilder( getOutputDirPath(moduleName, "abi_classes"), ).toString() } + if (argMap.hasAll(KotlinBuilderFlags.ASSOCIATES_ABI_JAR)) { + associatesAbiClasses = + workingDir + .resolveNewDirectories( + getOutputDirPath(moduleName, "associates_abi_classes"), + ).toString() + } generatedClasses = workingDir .resolveNewDirectories(getOutputDirPath(moduleName, "generated_classes")) diff --git a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/CompilationTask.kt b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/CompilationTask.kt index 87fd7a8e0..0399065fd 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/CompilationTask.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/CompilationTask.kt @@ -288,6 +288,21 @@ internal fun JvmCompilationTask.createAbiJar() = it.execute() } +/** + * Produce the associates ABI jar (with internal visibility preserved). + */ +internal fun JvmCompilationTask.createAssociatesAbiJar() = + JarCreator( + path = Paths.get(outputs.associatesAbiJar), + normalize = true, + verbose = false, + ).also { + it.addDirectory(Paths.get(directories.associatesAbiClasses)) + it.addDirectory(Paths.get(directories.generatedClasses)) + it.setJarOwner(info.label, info.bazelRuleKind) + it.execute() + } + /** * Produce a jar of sources generated by KAPT. */ diff --git a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/InternalCompilerPlugins.kt b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/InternalCompilerPlugins.kt index 6dccca731..f63dada1d 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/InternalCompilerPlugins.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/InternalCompilerPlugins.kt @@ -24,4 +24,5 @@ class InternalCompilerPlugins constructor( val skipCodeGen: KotlinToolchain.CompilerPlugin, val kapt: KotlinToolchain.CompilerPlugin, val jdeps: KotlinToolchain.CompilerPlugin, + val associatesAbiGen: KotlinToolchain.CompilerPlugin, ) 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 32b8260d0..d6538a098 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 @@ -100,6 +100,14 @@ class KotlinJvmTaskExecutor( given(outputs.jar).empty { plugin(plugins.skipCodeGen) } + }.given(outputs.associatesAbiJar) + .notEmpty { + plugin(plugins.associatesAbiGen) { + flag("outputDir", directories.associatesAbiClasses) + if (info.removeDebugInfo) { + flag("removeDebugInfo", "true") + } + } }, printOnFail = false, ) @@ -136,6 +144,9 @@ class KotlinJvmTaskExecutor( if (outputs.abijar.isNotEmpty()) { context.execute("create abi jar", ::createAbiJar) } + if (outputs.associatesAbiJar.isNotEmpty()) { + context.execute("create associates abi jar", ::createAssociatesAbiJar) + } if (outputs.generatedJavaSrcJar.isNotEmpty()) { context.execute("creating KAPT generated Java source jar", ::createGeneratedJavaSrcJar) } diff --git a/src/main/kotlin/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt b/src/main/kotlin/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt index d8ae3fcca..9d5787e02 100644 --- a/src/main/kotlin/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt +++ b/src/main/kotlin/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt @@ -29,6 +29,7 @@ class KotlinToolchain private constructor( val jvmAbiGen: CompilerPlugin, val skipCodeGen: CompilerPlugin, val jdepsGen: CompilerPlugin, + val associatesAbiGen: CompilerPlugin, ) { companion object { private val JVM_ABI_PLUGIN by lazy { @@ -66,6 +67,13 @@ class KotlinToolchain private constructor( ).toPath() } + private val ASSOCIATES_ABI_GEN_PLUGIN by lazy { + BazelRunFiles + .resolveVerifiedFromProperty( + "@rules_kotlin...associates-abi-gen", + ).toPath() + } + private val KOTLINC by lazy { BazelRunFiles .resolveVerifiedFromProperty( @@ -116,6 +124,7 @@ class KotlinToolchain private constructor( KOTLINX_SERIALIZATION_CORE_JVM.toFile(), KOTLINX_SERIALIZATION_JSON.toFile(), KOTLINX_SERIALIZATION_JSON_JVM.toFile(), + ASSOCIATES_ABI_GEN_PLUGIN.verified().absoluteFile, ) @JvmStatic @@ -130,6 +139,7 @@ class KotlinToolchain private constructor( kotlinxSerializationCoreJvm: File, kotlinxSerializationJson: File, kotlinxSerializationJsonJvm: File, + associatesAbiGenFile: File, ): KotlinToolchain = KotlinToolchain( listOf( @@ -139,6 +149,7 @@ class KotlinToolchain private constructor( jvmAbiGenFile, skipCodeGenFile, jdepsGenFile, + associatesAbiGenFile, kotlinxSerializationCoreJvm, kotlinxSerializationJson, kotlinxSerializationJsonJvm, @@ -163,6 +174,11 @@ class KotlinToolchain private constructor( kaptFile.path, "org.jetbrains.kotlin.kapt3", ), + associatesAbiGen = + CompilerPlugin( + associatesAbiGenFile.path, + "io.bazel.kotlin.plugin.ExperimentalAssociatesAbiGen", + ), ) } diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/associates/BUILD.bazel b/src/main/kotlin/io/bazel/kotlin/plugin/associates/BUILD.bazel new file mode 100644 index 000000000..29b40f357 --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/associates/BUILD.bazel @@ -0,0 +1,47 @@ +# Copyright 2024 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("@rules_java//java:defs.bzl", "java_binary") +load("//kotlin/internal/utils:generate_jvm_service.bzl", "generate_jvm_service") +load("//src/main/kotlin:bootstrap.bzl", "kt_bootstrap_library") + +# The compiler binary, this is co-located in the kotlin compiler classloader. +kt_bootstrap_library( + name = "associates-abi-gen-lib", + srcs = glob(["*.kt"]), + visibility = ["//src:__subpackages__"], + deps = [ + "//kotlin/compiler:jvm-abi-gen", + "//kotlin/compiler:kotlin-compiler", + ], +) + +# services to integrate with the plugin. +generate_jvm_service( + name = "associates-abi-gen-services", + services = { + "io.bazel.kotlin.plugin.associates.ExperimentalAssociatesAbiGenCommandLineProcessor": "org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor", + "io.bazel.kotlin.plugin.associates.ExperimentalAssociatesAbiGenRegistrar": "org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar", + }, +) + +# The plugin binary. +java_binary( + name = "associates-abi-gen", + visibility = ["//src:__subpackages__"], + runtime_deps = [ + ":associates-abi-gen-lib", + ":associates-abi-gen-services", + ], +) diff --git a/src/main/kotlin/io/bazel/kotlin/plugin/associates/ExperimentalAssociatesAbiGen.kt b/src/main/kotlin/io/bazel/kotlin/plugin/associates/ExperimentalAssociatesAbiGen.kt new file mode 100644 index 000000000..f9e924f4e --- /dev/null +++ b/src/main/kotlin/io/bazel/kotlin/plugin/associates/ExperimentalAssociatesAbiGen.kt @@ -0,0 +1,178 @@ +/* + * Copyright 2024 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 io.bazel.kotlin.plugin.associates + +import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption +import org.jetbrains.kotlin.compiler.plugin.CliOption +import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException +import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor +import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar +import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.CompilerConfigurationKey +import org.jetbrains.kotlin.jvm.abi.JvmAbiComponentRegistrar +import org.jetbrains.kotlin.jvm.abi.JvmAbiConfigurationKeys + +@OptIn(ExperimentalCompilerApi::class) +class ExperimentalAssociatesAbiGenCommandLineProcessor : CommandLineProcessor { + companion object { + const val COMPILER_PLUGIN_ID = + "io.bazel.kotlin.plugin.ExperimentalAssociatesAbiGen" + + val OUTPUT_DIR = + CompilerConfigurationKey