Skip to content

Commit 661142b

Browse files
authored
Add support for experimental treatInternalAsPrivate (#1248)
* Add support for experimental treatInternalAsPrivate * Fix ktlint violations * Add experimental_use_public_only_abi_jars docs * Add option to tag rule as kt_public_only_in_abi_plugin_incompatible * Regenerate docs * Split treatInternalAsPrivate and removePrivateClasses flags * Add failure message
1 parent f20ef32 commit 661142b

File tree

9 files changed

+158
-4
lines changed

9 files changed

+158
-4
lines changed

CompileAvoidance.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,29 @@ kt_jvm_library(
3838
tags = ["kt_abi_plugin_incompatible"],
3939
)
4040
```
41+
42+
Depending on your compiler version you may find non-public symbols in your ABI jar such as [internal declarations](https://youtrack.jetbrains.com/issue/KT-65690) or [effectively private classes](https://youtrack.jetbrains.com/issue/KT-64590).
43+
Exclusion of these symbols from the ABI jar can be enabled through the `experimental_treat_internal_as_private_in_abi_jars` and `experimental_remove_private_classes_in_abi_jars` flags in addition to `experimental_use_abi_jars` flag when defining the toolchain as follows
44+
45+
```python
46+
load("//kotlin:core.bzl", "define_kt_toolchain")
47+
48+
49+
define_kt_toolchain(
50+
name = "kotlin_toolchain",
51+
experimental_use_abi_jars = True,
52+
experimental_treat_internal_as_private_in_abi_jars = True,
53+
experimental_remove_private_classes_in_abi_jars = True,
54+
)
55+
```
56+
57+
If you encounter bugs in older compiler versions such as [KT-71525](https://youtrack.jetbrains.com/issue/KT-71525) then ABI generation with only public symbols can be disabled on a per target basis by setting the following tags
58+
59+
```python
60+
load("//kotlin:jvm.bzl", "kt_jvm_library")
61+
62+
kt_jvm_library(
63+
name = "framework",
64+
tags = ["kt_treat_internal_as_private_in_abi_plugin_incompatible", "kt_remove_private_classes_in_abi_plugin_incompatible"],
65+
)
66+
```

docs/kotlin.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -505,10 +505,12 @@ This allows setting options and dependencies independently from the initial plug
505505
load("@rules_kotlin//kotlin:core.bzl", "define_kt_toolchain")
506506

507507
define_kt_toolchain(<a href="#define_kt_toolchain-name">name</a>, <a href="#define_kt_toolchain-language_version">language_version</a>, <a href="#define_kt_toolchain-api_version">api_version</a>, <a href="#define_kt_toolchain-jvm_target">jvm_target</a>, <a href="#define_kt_toolchain-experimental_use_abi_jars">experimental_use_abi_jars</a>,
508-
<a href="#define_kt_toolchain-experimental_strict_kotlin_deps">experimental_strict_kotlin_deps</a>, <a href="#define_kt_toolchain-experimental_report_unused_deps">experimental_report_unused_deps</a>,
509-
<a href="#define_kt_toolchain-experimental_reduce_classpath_mode">experimental_reduce_classpath_mode</a>, <a href="#define_kt_toolchain-experimental_multiplex_workers">experimental_multiplex_workers</a>, <a href="#define_kt_toolchain-javac_options">javac_options</a>,
510-
<a href="#define_kt_toolchain-kotlinc_options">kotlinc_options</a>, <a href="#define_kt_toolchain-jvm_stdlibs">jvm_stdlibs</a>, <a href="#define_kt_toolchain-jvm_runtime">jvm_runtime</a>, <a href="#define_kt_toolchain-jacocorunner">jacocorunner</a>, <a href="#define_kt_toolchain-exec_compatible_with">exec_compatible_with</a>,
511-
<a href="#define_kt_toolchain-target_compatible_with">target_compatible_with</a>, <a href="#define_kt_toolchain-target_settings">target_settings</a>)
508+
<a href="#define_kt_toolchain-experimental_treat_internal_as_private_in_abi_jars">experimental_treat_internal_as_private_in_abi_jars</a>,
509+
<a href="#define_kt_toolchain-experimental_remove_private_classes_in_abi_jars">experimental_remove_private_classes_in_abi_jars</a>, <a href="#define_kt_toolchain-experimental_strict_kotlin_deps">experimental_strict_kotlin_deps</a>,
510+
<a href="#define_kt_toolchain-experimental_report_unused_deps">experimental_report_unused_deps</a>, <a href="#define_kt_toolchain-experimental_reduce_classpath_mode">experimental_reduce_classpath_mode</a>,
511+
<a href="#define_kt_toolchain-experimental_multiplex_workers">experimental_multiplex_workers</a>, <a href="#define_kt_toolchain-javac_options">javac_options</a>, <a href="#define_kt_toolchain-kotlinc_options">kotlinc_options</a>, <a href="#define_kt_toolchain-jvm_stdlibs">jvm_stdlibs</a>,
512+
<a href="#define_kt_toolchain-jvm_runtime">jvm_runtime</a>, <a href="#define_kt_toolchain-jacocorunner">jacocorunner</a>, <a href="#define_kt_toolchain-exec_compatible_with">exec_compatible_with</a>, <a href="#define_kt_toolchain-target_compatible_with">target_compatible_with</a>,
513+
<a href="#define_kt_toolchain-target_settings">target_settings</a>)
512514
</pre>
513515

514516
Define the Kotlin toolchain.
@@ -523,6 +525,8 @@ Define the Kotlin toolchain.
523525
| <a id="define_kt_toolchain-api_version"></a>api_version | <p align="center"> - </p> | `None` |
524526
| <a id="define_kt_toolchain-jvm_target"></a>jvm_target | <p align="center"> - </p> | `None` |
525527
| <a id="define_kt_toolchain-experimental_use_abi_jars"></a>experimental_use_abi_jars | <p align="center"> - </p> | `False` |
528+
| <a id="define_kt_toolchain-experimental_treat_internal_as_private_in_abi_jars"></a>experimental_treat_internal_as_private_in_abi_jars | <p align="center"> - </p> | `False` |
529+
| <a id="define_kt_toolchain-experimental_remove_private_classes_in_abi_jars"></a>experimental_remove_private_classes_in_abi_jars | <p align="center"> - </p> | `False` |
526530
| <a id="define_kt_toolchain-experimental_strict_kotlin_deps"></a>experimental_strict_kotlin_deps | <p align="center"> - </p> | `None` |
527531
| <a id="define_kt_toolchain-experimental_report_unused_deps"></a>experimental_report_unused_deps | <p align="center"> - </p> | `None` |
528532
| <a id="define_kt_toolchain-experimental_reduce_classpath_mode"></a>experimental_reduce_classpath_mode | <p align="center"> - </p> | `None` |

kotlin/internal/jvm/compile.bzl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,20 @@ def _run_kt_builder_action(
539539
omit_if_empty = True,
540540
)
541541

542+
if not "kt_remove_private_classes_in_abi_plugin_incompatible" in ctx.attr.tags and toolchains.kt.experimental_remove_private_classes_in_abi_jars == True:
543+
args.add("--remove_private_classes_in_abi_jar", "true")
544+
545+
if not "kt_treat_internal_as_private_in_abi_plugin_incompatible" in ctx.attr.tags and toolchains.kt.experimental_treat_internal_as_private_in_abi_jars == True:
546+
if not "kt_remove_private_classes_in_abi_plugin_incompatible" in ctx.attr.tags and toolchains.kt.experimental_remove_private_classes_in_abi_jars == True:
547+
args.add("--treat_internal_as_private_in_abi_jar", "true")
548+
else:
549+
fail(
550+
"experimental_treat_internal_as_private_in_abi_jars without experimental_remove_private_classes_in_abi_jars is invalid." +
551+
"\nTo remove internal symbols from kotlin abi jars ensure experimental_remove_private_classes_in_abi_jars " +
552+
"and experimental_treat_internal_as_private_in_abi_jars are both enabled in define_kt_toolchain." +
553+
"\nAdditionally ensure the target does not contain the kt_remove_private_classes_in_abi_plugin_incompatible tag.",
554+
)
555+
542556
args.add("--build_kotlin", build_kotlin)
543557

544558
progress_message = "%s %%{label} { kt: %d, java: %d, srcjars: %d } for %s" % (

kotlin/internal/toolchains.bzl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ def _kotlin_toolchain_impl(ctx):
8686
"supports-multiplex-workers": "1" if ctx.attr.experimental_multiplex_workers else "0",
8787
},
8888
experimental_use_abi_jars = ctx.attr.experimental_use_abi_jars,
89+
experimental_treat_internal_as_private_in_abi_jars = ctx.attr.experimental_treat_internal_as_private_in_abi_jars,
90+
experimental_remove_private_classes_in_abi_jars = ctx.attr.experimental_remove_private_classes_in_abi_jars,
8991
experimental_strict_kotlin_deps = ctx.attr.experimental_strict_kotlin_deps,
9092
experimental_report_unused_deps = ctx.attr.experimental_report_unused_deps,
9193
experimental_reduce_classpath_mode = ctx.attr.experimental_reduce_classpath_mode,
@@ -204,6 +206,20 @@ _kt_toolchain = rule(
204206
`kt_abi_plugin_incompatible`""",
205207
default = False,
206208
),
209+
"experimental_treat_internal_as_private_in_abi_jars": attr.bool(
210+
doc = """This applies the following compiler plugin option:
211+
plugin:org.jetbrains.kotlin.jvm.abi:treatInternalAsPrivate=true
212+
Can be disabled for an individual target using the tag.
213+
`kt_treat_internal_as_private_in_abi_plugin_incompatible`""",
214+
default = False,
215+
),
216+
"experimental_remove_private_classes_in_abi_jars": attr.bool(
217+
doc = """This applies the following compiler plugin option:
218+
plugin:org.jetbrains.kotlin.jvm.abi:removePrivateClasses=true
219+
Can be disabled for an individual target using the tag.
220+
`kt_remove_private_classes_in_abi_plugin_incompatible`""",
221+
default = False,
222+
),
207223
"experimental_strict_kotlin_deps": attr.string(
208224
doc = "Report strict deps violations",
209225
default = "off",
@@ -290,6 +306,8 @@ def define_kt_toolchain(
290306
api_version = None,
291307
jvm_target = None,
292308
experimental_use_abi_jars = False,
309+
experimental_treat_internal_as_private_in_abi_jars = False,
310+
experimental_remove_private_classes_in_abi_jars = False,
293311
experimental_strict_kotlin_deps = None,
294312
experimental_report_unused_deps = None,
295313
experimental_reduce_classpath_mode = None,
@@ -316,6 +334,8 @@ def define_kt_toolchain(
316334
_NOEXPERIMENTAL_USE_ABI_JARS: False,
317335
"//conditions:default": experimental_use_abi_jars,
318336
}),
337+
experimental_treat_internal_as_private_in_abi_jars = experimental_treat_internal_as_private_in_abi_jars,
338+
experimental_remove_private_classes_in_abi_jars = experimental_remove_private_classes_in_abi_jars,
319339
experimental_multiplex_workers = experimental_multiplex_workers,
320340
experimental_strict_kotlin_deps = experimental_strict_kotlin_deps,
321341
experimental_report_unused_deps = experimental_report_unused_deps,

src/main/kotlin/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ class KotlinBuilder
7777
DEBUG("--kotlin_debug_tags"),
7878
TASK_ID("--kotlin_task_id"),
7979
ABI_JAR("--abi_jar"),
80+
ABI_JAR_INTERNAL_AS_PRIVATE("--treat_internal_as_private_in_abi_jar"),
81+
ABI_JAR_REMOVE_PRIVATE_CLASSES("--remove_private_classes_in_abi_jar"),
8082
GENERATED_JAVA_SRC_JAR("--generated_java_srcjar"),
8183
GENERATED_JAVA_STUB_JAR("--kapt_generated_stub_jar"),
8284
GENERATED_CLASS_JAR("--kapt_generated_class_jar"),
@@ -161,6 +163,12 @@ class KotlinBuilder
161163
argMap.mandatorySingle(KotlinBuilderFlags.LANGUAGE_VERSION)
162164
strictKotlinDeps = argMap.mandatorySingle(KotlinBuilderFlags.STRICT_KOTLIN_DEPS)
163165
reducedClasspathMode = argMap.mandatorySingle(KotlinBuilderFlags.REDUCED_CLASSPATH_MODE)
166+
argMap.optionalSingle(KotlinBuilderFlags.ABI_JAR_INTERNAL_AS_PRIVATE)?.let {
167+
treatInternalAsPrivateInAbiJar = it == "true"
168+
}
169+
argMap.optionalSingle(KotlinBuilderFlags.ABI_JAR_REMOVE_PRIVATE_CLASSES)?.let {
170+
removePrivateClassesInAbiJar = it == "true"
171+
}
164172
this
165173
}
166174

src/main/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ class KotlinJvmTaskExecutor
8787
.notEmpty {
8888
plugin(plugins.jvmAbiGen) {
8989
flag("outputDir", directories.abiClasses)
90+
if (info.treatInternalAsPrivateInAbiJar) {
91+
flag("treatInternalAsPrivate", "true")
92+
}
93+
if (info.removePrivateClassesInAbiJar) {
94+
flag("removePrivateClasses", "true")
95+
}
9096
}
9197
given(outputs.jar).empty {
9298
plugin(plugins.skipCodeGen)

src/main/protobuf/kotlin_model.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ message CompilationTaskInfo {
8181
string strict_kotlin_deps = 10;
8282
// Optimize classpath by removing dependencies not required for compilation
8383
string reduced_classpath_mode = 11;
84+
// Internal declarations are treaded as private for abi.jar generation
85+
bool treat_internal_as_private_in_abi_jar = 12;
86+
// Private classes are removed in abi.jar generation
87+
bool remove_private_classes_in_abi_jar = 13;
8488
}
8589

8690
// Nested messages not marked with stable could be refactored.

src/test/kotlin/io/bazel/kotlin/builder/KotlinJvmTestBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ public TaskBuilder outputAbiJar() {
228228
return this;
229229
}
230230

231+
public TaskBuilder publicOnlyAbiJar() {
232+
taskBuilder.getInfoBuilder().setTreatInternalAsPrivateInAbiJar(true).setRemovePrivateClassesInAbiJar(true);
233+
return this;
234+
}
235+
231236
public TaskBuilder generatedSourceJar() {
232237
taskBuilder.getOutputsBuilder()
233238
.setGeneratedJavaSrcJar(instanceRoot().resolve("gen-src.jar").toAbsolutePath().toString());

src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmAbiTest.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@
2222
import org.junit.runner.RunWith;
2323
import org.junit.runners.JUnit4;
2424

25+
import java.io.IOException;
26+
import java.util.zip.ZipEntry;
27+
import java.util.zip.ZipFile;
28+
29+
import static org.hamcrest.MatcherAssert.assertThat;
30+
import static org.hamcrest.core.Is.is;
31+
import static org.hamcrest.core.IsNot.not;
32+
import static org.hamcrest.core.IsNull.nullValue;
33+
2534
@RunWith(JUnit4.class)
2635
public class KotlinBuilderJvmAbiTest {
2736
private static final KotlinJvmTestBuilder ctx = new KotlinJvmTestBuilder();
@@ -60,4 +69,62 @@ public void testGeneratesAbiJarSource() {
6069
c.compileKotlin();
6170
});
6271
}
72+
73+
@Test
74+
public void testGeneratesPublicAbiOnly() throws IOException {
75+
Deps.Dep d = ctx.runCompileTask(
76+
c -> {
77+
c.addSource("AClass.kt", "package something;" + "class AClass{}");
78+
c.addSource("AnotherClass.kt", "package something;", "", "class AnotherClass{}");
79+
c.addSource("NonPublicClass.kt", "package something;", "", "internal class NonPublicClass{}");
80+
c.outputJar();
81+
c.outputAbiJar();
82+
c.publicOnlyAbiJar();
83+
c.compileKotlin();
84+
c.outputJdeps();
85+
});
86+
87+
String abiJarPath = d.compileJars()
88+
.stream()
89+
.filter( (name)->name.endsWith("abi.jar") )
90+
.findFirst()
91+
.orElse(null);
92+
93+
assertThat(abiJarPath, is(not(nullValue())));
94+
95+
ZipEntry entry = null;
96+
try( ZipFile zipFile = new ZipFile(abiJarPath) ) {
97+
entry = zipFile.getEntry("something/NonPublicClass.class");
98+
}
99+
assertThat(entry, is(nullValue()));
100+
}
101+
102+
103+
@Test
104+
public void testGeneratesAbiIncludingInternal() throws IOException {
105+
Deps.Dep d = ctx.runCompileTask(
106+
c -> {
107+
c.addSource("AClass.kt", "package something;" + "class AClass{}");
108+
c.addSource("AnotherClass.kt", "package something;", "", "class AnotherClass{}");
109+
c.addSource("NonPublicClass.kt", "package something;", "", "internal class NonPublicClass{}");
110+
c.outputJar();
111+
c.outputAbiJar();
112+
c.compileKotlin();
113+
c.outputJdeps();
114+
});
115+
116+
String abiJarPath = d.compileJars()
117+
.stream()
118+
.filter( (name)->name.endsWith("abi.jar") )
119+
.findFirst()
120+
.orElse(null);
121+
122+
assertThat(abiJarPath, is(not(nullValue())));
123+
124+
ZipEntry entry = null;
125+
try( ZipFile zipFile = new ZipFile(abiJarPath) ) {
126+
entry = zipFile.getEntry("something/NonPublicClass.class");
127+
}
128+
assertThat(entry, is(not(nullValue())));
129+
}
63130
}

0 commit comments

Comments
 (0)