[klib] Add an option to write out header klibs

The header klib is supposed to only contain the public abi of the module
similar to jvm-abi-gen. It is intended to be used as a dependency for other
klib compilations instead of the full klib for compilation avoidance.

^KT-60807
This commit is contained in:
Johan Bay
2023-05-09 14:29:21 +02:00
committed by Space Team
parent 829e0675f4
commit 0a612e4268
90 changed files with 1374 additions and 76 deletions
@@ -0,0 +1,10 @@
package lib
interface Interface {
fun getInt(): Int
}
fun getInterface(): Interface =
object : Interface {
override fun getInt(): Int = 10
}
@@ -0,0 +1,11 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
val i = getInterface()
val value = i.getInt()
if (value != 10) error("getInterface().getInt() is '$value', but is expected to be '10'")
return "OK"
}
@@ -0,0 +1,31 @@
package lib
interface I {
val iProperty: Int
fun iMethod(): Int
}
open class A : I {
override val iProperty: Int = 0
override fun iMethod(): Int = 10
val aProperty: Int = 20
fun aMethod(): Int = 30
inline fun aInlineMethod(): Int = 40
private class AB {}
companion object {
const val aConst: Int = 50
}
}
class B : A() {
val bProperty: Int = 60
fun bMethod(): Int = 70
inline fun bInlineMethod(): Int = 80
companion object {
const val bConst: Int = 90
}
}
@@ -0,0 +1,40 @@
package app
import lib.*
fun useI(i: I) {
i.iProperty
i.iMethod()
}
fun useA(a: A) {
a.iProperty
a.iMethod()
a.aProperty
a.aMethod()
a.aInlineMethod()
A.aConst
}
fun useB(b: B) {
b.iProperty
b.iMethod()
b.aProperty
b.aMethod()
b.aInlineMethod()
b.bProperty
b.bMethod()
b.bInlineMethod()
B.bConst
}
fun runAppAndReturnOk(): String {
useI(A())
useA(A())
useB(B())
return "OK"
}
@@ -0,0 +1,7 @@
package lib
object Object {
val x = 1
val y = 2
val z = x + y
}
@@ -0,0 +1,5 @@
package lib
val x = 1
val y = 2
val z = x + y
@@ -0,0 +1,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
if (Object.z != 3) error("lib.Object.z is ${Object.z}, but '3' was expected")
if (z != 3) error("lib.z is $z, but '3' was expected")
return "OK"
}
@@ -0,0 +1,5 @@
package lib
annotation class A(val value: String)
inline fun a() = A("OK")
@@ -0,0 +1,7 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
return a().value
}
@@ -0,0 +1,11 @@
package lib
interface Interface {
fun getInt(): Int
}
inline fun getCounter(crossinline init: () -> Int): Interface =
object : Interface {
var value = init()
override fun getInt(): Int = value++
}
@@ -0,0 +1,13 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
val a = lib.getCounter { 100 }
val x = a.getInt()
if (x != 100) error("a returned $x but expected '100'")
val y = a.getInt()
if (y != 101) error("a returned $y but expected '101'")
return "OK"
}
@@ -0,0 +1,10 @@
package lib
fun inlineCapture(s: String): String {
return with(StringBuilder()) {
val o = object {
override fun toString() = s
}
append(o)
}.toString()
}
@@ -0,0 +1,7 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
return inlineCapture("OK")
}
@@ -0,0 +1,19 @@
package lib
var result = "fail"
inline fun foo(crossinline s: () -> String) {
object {
private inline fun test(crossinline z: () -> String) {
result = object { //should be marked as public abi as there is no regenerated abject on inline
fun run(): String {
return "O"
}
}.run() + z()
}
fun foo() {
test { s() }
}
}.foo()
}
@@ -0,0 +1,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
foo {
"K"
}
return result
}
@@ -0,0 +1,4 @@
package lib
inline fun <reified T> safeCall(x: Any?, fn: (T) -> T): T? =
if (x is T) fn(x) else null
@@ -0,0 +1,13 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
val a = safeCall<Int>(10) { it * it }
if (a != 100) error("a is '$a', but is expected to be '100'")
val b = safeCall<Int>(null) { it * it }
if (b != null) error("b is '$b', but is expected to be 'null'")
return "OK"
}
@@ -0,0 +1,10 @@
package lib
enum class E {
A, B
}
inline fun value(x: E) = when (x) {
E.A -> "OK"
E.B -> "Fail"
}
@@ -0,0 +1,5 @@
package app
import lib.*
fun runAppAndReturnOk(): String = value(E.A)
@@ -0,0 +1,19 @@
package lib
var result = "fail"
inline fun foo(crossinline s: () -> String) {
object {
private inline fun test(crossinline z: () -> String) {
object {
fun run() {
result = z()
}
}.run()
}
fun foo() {
test { s() } // regenerated object should be marked as public abi
}
}.foo()
}
@@ -0,0 +1,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
foo {
"OK"
}
return result
}
@@ -0,0 +1,11 @@
package lib
inline fun anInlineFunction(crossinline crossInlineLamba: () -> Unit) {
Foo().apply {
barMethod { crossInlineLamba() }
}
}
class Foo {
fun barMethod(aLambda: () -> Unit) { aLambda() }
}
@@ -0,0 +1,9 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
var result = "Fail"
anInlineFunction { result = "OK" }
return result
}
@@ -0,0 +1,7 @@
package lib
class A private constructor(val x: Int) {
companion object {
fun create(x: Int): A = A(x * 2)
}
}
@@ -0,0 +1,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
val a = A.create(10)
if (a.x != 20) error("a.x is '${a.x}', but is expected to be '20'")
return "OK"
}
@@ -0,0 +1,6 @@
package lib
value class A private constructor(val value: String) {
companion object { fun a() = A("OK") }
inline fun b() = value
}
@@ -0,0 +1,7 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
return A.a().b()
}
@@ -0,0 +1,6 @@
package lib
val prop: Int = 1
fun func(): Int = 2
inline fun inlineFunc(): Int = 3
const val constant: Int = 4
@@ -0,0 +1,14 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
if (prop != 1) error("prop is '$prop', but is expected to be '1'")
val funcValue = func()
if (funcValue != 2) error("func() is '$funcValue', but is expected to be '2'")
val inlineFuncValue = inlineFunc()
if (inlineFuncValue != 3) error("inlineFunc() is '$inlineFuncValue', but is expected to be '3'")
if (constant != 4) error("constant is '$constant', but is expected to be '4'")
return "OK"
}