From 06b92958b4831752ea0941b18dc08535ac45a69e Mon Sep 17 00:00:00 2001
From: Alexander Sysoev
Date: Mon, 16 Jun 2025 11:53:57 +0200
Subject: [PATCH 1/6] Update doc for `RpcCall`
---
docs/pages/kotlinx-rpc/topics/0-8-0.topic | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/docs/pages/kotlinx-rpc/topics/0-8-0.topic b/docs/pages/kotlinx-rpc/topics/0-8-0.topic
index b61dfafd9..492c56f5d 100644
--- a/docs/pages/kotlinx-rpc/topics/0-8-0.topic
+++ b/docs/pages/kotlinx-rpc/topics/0-8-0.topic
@@ -222,6 +222,29 @@
+
+
+ RpcCall
changed parameter name and type for function's data:
+
+
+
+ class RpcCall(
+ val descriptor: RpcServiceDescriptor<*>,
+ val callableName: String,
+ val data: Any?,
+ val serviceId: Long,
+ )
+
+
+ class RpcCall(
+ val descriptor: RpcServiceDescriptor<*>,
+ val callableName: String,
+ val parameters: Array<Any?>,
+ val serviceId: Long,
+ )
+
+
+
For Ktor, HttpClient.rpc
extension function is now non-suspendable.
From 8e58235e67a9633970d250a01f8cf5570b1180af Mon Sep 17 00:00:00 2001
From: Alexander Sysoev
Date: Mon, 16 Jun 2025 12:07:45 +0200
Subject: [PATCH 2/6] Updated README.md
---
README.md | 55 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/README.md b/README.md
index 181b62fe1..18bb579d1 100644
--- a/README.md
+++ b/README.md
@@ -19,11 +19,8 @@ Build your RPC with already known language constructs and nothing more!
First, create your RPC service and define some methods:
```kotlin
-import kotlinx.rpc.RemoteService
-import kotlinx.rpc.annotations.Rpc
-
@Rpc
-interface AwesomeService : RemoteService {
+interface AwesomeService {
fun getNews(city: String): Flow
suspend fun daysUntilStableRelease(): Int
@@ -31,10 +28,7 @@ interface AwesomeService : RemoteService {
```
In your server code define how to respond by simply implementing the service:
```kotlin
-class AwesomeServiceImpl(
- val parameters: AwesomeParameters,
- override val coroutineContext: CoroutineContext,
-) : AwesomeService {
+class AwesomeServiceImpl(val parameters: AwesomeParameters) : AwesomeService {
override fun getNews(city: String): Flow {
return flow {
emit("Today is 23 degrees!")
@@ -66,8 +60,8 @@ fun main() {
}
}
- registerService { ctx ->
- AwesomeServiceImpl(AwesomeParameters(false, null), ctx)
+ registerService {
+ AwesomeServiceImpl(AwesomeParameters(false, null))
}
}
}
@@ -90,10 +84,8 @@ val service = rpcClient.withService()
service.daysUntilStableRelease()
-streamScoped {
- service.getNews("KotlinBurg").collect { article ->
- println(article)
- }
+service.getNews("KotlinBurg").collect { article ->
+ println(article)
}
```
@@ -106,6 +98,33 @@ Check out our [getting started guide](https://kotlin.github.io/kotlinx-rpc) for
To ensure that all IDE features of our compiler plugin work properly on IntelliJ-based IDEs, install the
[Kotlin External FIR Support](https://plugins.jetbrains.com/plugin/26480-kotlin-external-fir-support?noRedirect=true) plugin.
+## Kotlin compatibility
+We support all stable Kotlin versions starting from 2.0.0:
+- 2.0.0, 2.0.10, 2.0.20, 2.0.21
+- 2.1.0, 2.1.10, 2.1.20, 2.1.21
+
+For a full compatibility checklist,
+see [Versions](https://kotlin.github.io/kotlinx-rpc/versions.html).
+
+## Supported Platforms
+
+`kotlinx.rpc` is a KMP library, so we aim to support all available platforms.
+
+However, we are also a multi-module library, meaning that some modules may not support some platforms.
+
+Current high-level status:
+
+| Subsystem | Supported Platforms |
+|-----------|--------------------------------------------|
+| Core | JVM, Native, JS, WasmJs, WasmWASI, Windows |
+| kRPC | JVM, Native, JS, WasmJs, Windows |
+| gRPC | JVM (in JVM-only projects) |
+
+For more detailed module by module information,
+check out our [platform support table](https://kotlin.github.io/kotlinx-rpc/platforms.html).
+
+For information about gRPC, see [gRPC Integration](#grpc-integration)
+
### Gradle plugins
`kotlinx.rpc` provides Gradle plugin `org.jetbrains.kotlinx.rpc.plugin`
@@ -174,14 +193,6 @@ For more information on gRPC usage,
see the [official documentation](https://kotlin.github.io/kotlinx-rpc/grpc-configuration.html).
For a working example, see the [sample gRPC project](/samples/grpc-app).
-## Kotlin compatibility
-We support all stable Kotlin versions starting from 2.0.0:
-- 2.0.0, 2.0.10, 2.0.20, 2.0.21
-- 2.1.0, 2.1.10, 2.1.20, 2.1.21
-
-For a full compatibility checklist,
-see [Versions](https://kotlin.github.io/kotlinx-rpc/versions.html).
-
## JetBrains Product
`kotlinx.rpc` is an official [JetBrains](https://jetbrains.com) product and is primarily developed by the team at JetBrains, with
From 24022ebce3a058c73b72fac0db09c017990e6528 Mon Sep 17 00:00:00 2001
From: Alexander Sysoev
Date: Mon, 16 Jun 2025 13:36:25 +0200
Subject: [PATCH 3/6] Updated targets setup
---
.../src/main/kotlin/util/OptionalProperty.kt | 41 ++++++++++++++-----
.../main/kotlin/util/ProjectKotlinConfig.kt | 38 +++++++----------
krpc/gradle.properties | 4 +-
krpc/krpc-test/gradle.properties | 2 +-
.../targets-since-kotlin-lookup.json | 15 ++++---
5 files changed, 58 insertions(+), 42 deletions(-)
diff --git a/gradle-conventions/common/src/main/kotlin/util/OptionalProperty.kt b/gradle-conventions/common/src/main/kotlin/util/OptionalProperty.kt
index 4542b5154..845c0d0ec 100644
--- a/gradle-conventions/common/src/main/kotlin/util/OptionalProperty.kt
+++ b/gradle-conventions/common/src/main/kotlin/util/OptionalProperty.kt
@@ -6,24 +6,43 @@ package util
import org.gradle.api.Project
import kotlin.reflect.KProperty
+import kotlin.text.replaceFirstChar
+
+class OptionalProperty(private val target: Project, private val subpaths: Array) {
+ private var cachedValue: Boolean? = null
-class OptionalProperty(private val target: Project) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
- return getValue("kotlinx.rpc.${property.name}")
+ return cachedValue ?: target.getValue(property.name, subpaths).also { cachedValue = it }
}
+}
+
+private fun Project.getValue(propertyName: String, subpaths: Array): Boolean {
+ val subpathProperty = subpaths
+ .joinToString(".", postfix = ".")
+ .takeIf { it != "." && it.isNotEmpty() }
+ ?: ""
+
+ val subpathCamelCase = subpaths
+ .joinToString("") { it.replaceFirstChar(Char::titlecase) }
+ .replaceFirstChar { it.lowercase() }
+
+ val name = propertyName
+ .removePrefix(subpathCamelCase)
+ .replaceFirstChar { it.lowercase() }
+
+ val fullName = "kotlinx.rpc.$subpathProperty$name"
- fun getValue(propName: String): Boolean {
- return when {
- target.hasProperty(propName) -> (target.properties[propName] as String).toBoolean()
- else -> false
- }
+ return when {
+ hasProperty(fullName) -> (properties[fullName] as? String)?.toBooleanStrictOrNull()
+ ?: error("Invalid value for '$fullName' property: ${properties[fullName]}")
+ else -> false
}
}
-fun Project.optionalProperty(): OptionalProperty {
- return OptionalProperty(this)
+fun Project.optionalProperty(vararg subpaths: String): OptionalProperty {
+ return OptionalProperty(this, subpaths)
}
-fun Project.optionalProperty(name: String): Boolean {
- return OptionalProperty(this).getValue(name)
+fun Project.optionalPropertyValue(name: String, vararg subpaths: String): Boolean {
+ return getValue(name, subpaths)
}
diff --git a/gradle-conventions/common/src/main/kotlin/util/ProjectKotlinConfig.kt b/gradle-conventions/common/src/main/kotlin/util/ProjectKotlinConfig.kt
index 8028f1db5..6e5724fcf 100644
--- a/gradle-conventions/common/src/main/kotlin/util/ProjectKotlinConfig.kt
+++ b/gradle-conventions/common/src/main/kotlin/util/ProjectKotlinConfig.kt
@@ -35,12 +35,6 @@ private fun loadTargetsSinceKotlinLookupTable(rootDir: String): Map
@@ -75,7 +77,7 @@ class ProjectKotlinConfig(
!kotlinMasterBuild && targetFunction.parameters.size == 1 && isIncluded(
targetName = targetFunction.name,
lookupTable = nativeLookup,
- )
+ ) && !optionalPropertyValue(targetFunction.name, "exclude")
}.map { function ->
function.call(kmp) as KotlinTarget
}
@@ -83,21 +85,9 @@ class ProjectKotlinConfig(
fun Project.withKotlinConfig(configure: ProjectKotlinConfig.() -> Unit) {
val kotlinVersion: KotlinVersion by extra
- val excludeJvm: Boolean by optionalProperty()
- val excludeJs: Boolean by optionalProperty()
- val excludeWasmJs: Boolean by optionalProperty()
- val excludeWasmJsD8: Boolean by optionalProperty()
- val excludeWasmWasi: Boolean by optionalProperty()
- val excludeNative: Boolean by optionalProperty()
ProjectKotlinConfig(
project = project,
kotlinVersion = kotlinVersion,
- jvm = !excludeJvm,
- js = !excludeJs,
- wasmJs = !excludeWasmJs,
- wasmJsD8 = !excludeWasmJsD8,
- wasmWasi = !excludeWasmWasi,
- native = !excludeNative,
).configure()
}
diff --git a/krpc/gradle.properties b/krpc/gradle.properties
index ae9b55854..b41a299a8 100644
--- a/krpc/gradle.properties
+++ b/krpc/gradle.properties
@@ -3,4 +3,6 @@
#
# https://github.com/oshai/kotlin-logging/issues/433
-kotlinx.rpc.excludeWasmWasi=true
+kotlinx.rpc.exclude.wasmWasi=true
+kotlinx.rpc.exclude.watchosArm32=true
+kotlinx.rpc.exclude.watchosDeviceArm64=true
diff --git a/krpc/krpc-test/gradle.properties b/krpc/krpc-test/gradle.properties
index 825c4ae92..db06764d8 100644
--- a/krpc/krpc-test/gradle.properties
+++ b/krpc/krpc-test/gradle.properties
@@ -3,4 +3,4 @@
#
# tests fail with some obscure reason
-kotlinx.rpc.excludeWasmJsD8=true
+kotlinx.rpc.exclude.wasmJsD8=true
diff --git a/versions-root/targets-since-kotlin-lookup.json b/versions-root/targets-since-kotlin-lookup.json
index 239c0e333..6248a73d8 100644
--- a/versions-root/targets-since-kotlin-lookup.json
+++ b/versions-root/targets-since-kotlin-lookup.json
@@ -5,7 +5,7 @@
"wasmJs": "*",
"wasmWasi": "*",
- "mingwX64": "-",
+ "mingwX64": "*",
"linuxX64": "*",
"linuxArm64": "*",
@@ -15,15 +15,20 @@
"iosSimulatorArm64": "*",
"watchosX64": "*",
- "watchosArm32": "-",
+ "watchosArm32": "*",
"watchosArm64": "*",
"watchosSimulatorArm64": "*",
- "watchosDeviceArm64": "-",
+ "watchosDeviceArm64": "*",
"tvosX64": "*",
"tvosArm64": "*",
- "tvosSimulatorArm64": "-",
+ "tvosSimulatorArm64": "*",
"macosX64": "*",
- "macosArm64": "*"
+ "macosArm64": "*",
+
+ "androidNativeArm32": "-",
+ "androidNativeArm64": "-",
+ "androidNativeX86": "-",
+ "androidNativeX64": "-"
}
From 990fc66e4632ddaa04ac24e37ebd8e9712ddb104 Mon Sep 17 00:00:00 2001
From: Alexander Sysoev
Date: Mon, 16 Jun 2025 16:19:57 +0200
Subject: [PATCH 4/6] Added platforms table
---
.github/workflows/platforms.yml | 19 ++
README.md | 10 +-
build.gradle.kts | 5 +
docs/pages/kotlinx-rpc/rpc.tree | 1 +
docs/pages/kotlinx-rpc/topics/platforms.topic | 167 ++++++++++
.../src/main/kotlin/util/platformTable.kt | 309 ++++++++++++++++++
.../kotlin/conventions-publishing.gradle.kts | 5 +-
7 files changed, 509 insertions(+), 7 deletions(-)
create mode 100644 .github/workflows/platforms.yml
create mode 100644 docs/pages/kotlinx-rpc/topics/platforms.topic
create mode 100644 gradle-conventions/common/src/main/kotlin/util/platformTable.kt
diff --git a/.github/workflows/platforms.yml b/.github/workflows/platforms.yml
new file mode 100644
index 000000000..d1d8269e9
--- /dev/null
+++ b/.github/workflows/platforms.yml
@@ -0,0 +1,19 @@
+name: Check PR Labels
+
+on:
+ pull_request:
+
+permissions:
+ contents: read
+
+jobs:
+ verify-platforms-table:
+ name: Verify Platforms Table
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Sources
+ uses: actions/checkout@v4
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v3
+ - name: Check Platforms Table
+ run: ./gradlew verifyPlatformsTable --no-configuration-cache
diff --git a/README.md b/README.md
index 18bb579d1..5fd2383ef 100644
--- a/README.md
+++ b/README.md
@@ -114,11 +114,11 @@ However, we are also a multi-module library, meaning that some modules may not s
Current high-level status:
-| Subsystem | Supported Platforms |
-|-----------|--------------------------------------------|
-| Core | JVM, Native, JS, WasmJs, WasmWASI, Windows |
-| kRPC | JVM, Native, JS, WasmJs, Windows |
-| gRPC | JVM (in JVM-only projects) |
+| Subsystem | Supported Platforms |
+|-----------|--------------------------------------------------|
+| Core | Jvm, Js, WasmJs, WasmWasi, Apple, Linux, Windows |
+| kRPC | Jvm, Js, WasmJs, Apple, Linux, Windows |
+| gRPC | Jvm (in Jvm-only projects) |
For more detailed module by module information,
check out our [platform support table](https://kotlin.github.io/kotlinx-rpc/platforms.html).
diff --git a/build.gradle.kts b/build.gradle.kts
index a1112d534..74f2a63d3 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -6,7 +6,9 @@ import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import util.configureApiValidation
import util.configureNpm
import util.configureProjectReport
+import util.registerDumpPlatformTableTask
import util.libs
+import util.registerVerifyPlatformTableTask
plugins {
alias(libs.plugins.serialization) apply false
@@ -21,6 +23,9 @@ configureProjectReport()
configureNpm()
configureApiValidation()
+registerDumpPlatformTableTask()
+registerVerifyPlatformTableTask()
+
val kotlinVersion = rootProject.libs.versions.kotlin.lang.get()
val kotlinCompiler = rootProject.libs.versions.kotlin.compiler.get()
diff --git a/docs/pages/kotlinx-rpc/rpc.tree b/docs/pages/kotlinx-rpc/rpc.tree
index 979360ba4..aab8e8679 100644
--- a/docs/pages/kotlinx-rpc/rpc.tree
+++ b/docs/pages/kotlinx-rpc/rpc.tree
@@ -39,6 +39,7 @@
+
diff --git a/docs/pages/kotlinx-rpc/topics/platforms.topic b/docs/pages/kotlinx-rpc/topics/platforms.topic
new file mode 100644
index 000000000..30b4c832b
--- /dev/null
+++ b/docs/pages/kotlinx-rpc/topics/platforms.topic
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+ kotlinx.rpc
is a KMP library, so we aim to support all available platforms.
+
+ However, we are also a multi-module library, meaning that some modules may not support some platforms.
+
+ Current high-level status:
+
+
+
+ Subsystem |
+ Supported Platforms |
+
+
+ Core |
+ Jvm, Js, WasmJs, WasmWasi, Apple, Linux, Windows |
+
+
+ kRPC |
+ Jvm, Js, WasmJs, Apple, Linux, Windows |
+
+
+ gRPC |
+ Jvm (in Jvm-only projects) |
+
+
+
+
+ The following table contains a list of all published modules and their supported platforms:
+
+
+
+ We are working on making the library more portable so that it can be used on more platforms.
+
+
diff --git a/gradle-conventions/common/src/main/kotlin/util/platformTable.kt b/gradle-conventions/common/src/main/kotlin/util/platformTable.kt
new file mode 100644
index 000000000..7078cc15d
--- /dev/null
+++ b/gradle-conventions/common/src/main/kotlin/util/platformTable.kt
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package util
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.TaskAction
+import org.gradle.kotlin.dsl.register
+import org.gradle.kotlin.dsl.the
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
+import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
+import org.jetbrains.kotlin.gradle.targets.js.KotlinWasmTargetType
+import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWasmJsTargetDsl
+import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWasmWasiTargetDsl
+import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
+import java.io.File
+import java.nio.file.Files
+
+private val PLATFORM_TOPIC_PATH = File("docs/pages/kotlinx-rpc/topics/platforms.topic")
+
+private const val TABLE_START_TAG = "PLATFORMS_TABLE_START"
+private const val TABLE_END_TAG = "PLATFORMS_TABLE_END"
+
+enum class TableColumn {
+ Jvm, Js, Wasm, Native;
+}
+
+sealed interface PlatformTarget {
+ val name: String
+ val subtargets: List
+
+ class Group(
+ override val name: String,
+ override val subtargets: List,
+ ) : PlatformTarget
+
+ class LeafTarget(override val name: String) : PlatformTarget {
+ override val subtargets: List = emptyList()
+ }
+}
+
+sealed interface PlatformsDescription {
+ object None : PlatformsDescription
+
+ object JvmOnly : PlatformsDescription
+
+ class Kmp(val platforms: Map) : PlatformsDescription
+}
+
+abstract class DumpPlatformsTask : DefaultTask() {
+ @get:InputFile
+ abstract val input: Property
+
+ @get:OutputFile
+ abstract val output: Property
+
+ @TaskAction
+ fun dump() {
+ val input = input.get()
+ if (!input.exists()) {
+ throw GradleException("File ${input.absolutePath} doesn't exist")
+ }
+
+ val output = output.get()
+ if (!output.exists()) {
+ Files.createFile(output.toPath())
+ }
+
+ val modules = collectPlatforms()
+
+ updateTable(input, output, modules)
+ }
+
+ private fun collectPlatforms(): Map {
+ return project.rootProject.allprojects.mapNotNull { subproject ->
+ if (!subproject.isPublicModule) {
+ return@mapNotNull null
+ }
+
+ val platforms: PlatformsDescription = when {
+ subproject.plugins.hasPlugin(KOTLIN_JVM_PLUGIN_ID) -> {
+ PlatformsDescription.JvmOnly
+ }
+
+ subproject.plugins.hasPlugin(KOTLIN_MULTIPLATFORM_PLUGIN_ID) -> {
+ platformsDescriptionKmp(subproject)
+ }
+
+ else -> PlatformsDescription.None
+ }
+
+ subproject.name to platforms
+ }.toMap()
+ }
+
+ private fun platformsDescriptionKmp(subproject: Project): PlatformsDescription.Kmp {
+ val mapped = subproject
+ .the()
+ .targets
+ .groupBy { target ->
+ target.platformType
+ }
+ .mapValues { (platform, targets) ->
+ when (platform) {
+ KotlinPlatformType.jvm -> {
+ PlatformTarget.LeafTarget(TableColumn.Jvm.name.lowercase())
+ }
+
+ KotlinPlatformType.js -> {
+ val subtargets = targets.jsOrWasmSubTargets("js", subproject) {
+ it is KotlinJsIrTarget
+ }
+
+ PlatformTarget.Group(TableColumn.Js.name, subtargets)
+ }
+
+ KotlinPlatformType.wasm -> {
+ val jsSubtargets = targets.jsOrWasmSubTargets("wasmJs", subproject) {
+ it is KotlinWasmJsTargetDsl && it.wasmTargetType == KotlinWasmTargetType.JS
+ }
+
+ val wasiSubtargets = targets.jsOrWasmSubTargets("wasmWasi", subproject) {
+ it is KotlinWasmWasiTargetDsl && it.wasmTargetType == KotlinWasmTargetType.WASI
+ }
+
+ val wasmSubtargets = listOfNotNull(
+ PlatformTarget.Group("wasmJs", jsSubtargets).takeIf { jsSubtargets.isNotEmpty() },
+ PlatformTarget.Group("wasmWasi", wasiSubtargets).takeIf { wasiSubtargets.isNotEmpty() },
+ )
+
+ PlatformTarget.Group(TableColumn.Wasm.name, wasmSubtargets)
+ }
+
+ KotlinPlatformType.native -> {
+ PlatformTarget.Group(
+ name = TableColumn.Native.name,
+ subtargets = listOf(
+ PlatformTarget.Group(
+ name = "apple",
+ subtargets = listOf(
+ targets.nativeGroup("ios"),
+ targets.nativeGroup("macos"),
+ targets.nativeGroup("watchos"),
+ targets.nativeGroup("tvos"),
+ ),
+ ),
+ targets.nativeGroup("linux"),
+ targets.nativeGroup("windows", "mingw"),
+ )
+ )
+ }
+
+ KotlinPlatformType.common, KotlinPlatformType.androidJvm -> null
+ }
+ }
+ .mapNotNull { (platform, target) -> target?.let { platform to it } }
+ .toMap()
+
+ return PlatformsDescription.Kmp(mapped)
+ }
+
+ private fun List.jsOrWasmSubTargets(
+ name: String,
+ project: Project,
+ condition: (KotlinTarget) -> Boolean,
+ ): List {
+ val foundTargets = filter(condition)
+ .filterIsInstance()
+
+ if (foundTargets.isEmpty()) {
+ return emptyList()
+ }
+
+ if (foundTargets.size > 1) {
+ error("Multiple $name targets are not supported (project ${project.name})")
+ }
+
+ val jsSubtargets = foundTargets.single().subTargets.map { subTargetWithBinary ->
+ PlatformTarget.LeafTarget(subTargetWithBinary.name)
+ }
+
+ return jsSubtargets
+ }
+
+ private fun List.nativeGroup(name: String, prefix: String = name): PlatformTarget.Group {
+ return PlatformTarget.Group(
+ name = name,
+ subtargets = filter { it.name.startsWith(prefix) }.map { PlatformTarget.LeafTarget(it.name) },
+ )
+ }
+
+ private fun updateTable(input: File, output: File, modules: Map) {
+ val original = input.readLines(Charsets.UTF_8)
+ val tableStart = original.indexOfFirst { it.contains(TABLE_START_TAG) }
+ val tableEnd = original.indexOfFirst { it.contains(TABLE_END_TAG) }
+
+ if (tableStart == -1 || tableEnd == -1) {
+ throw GradleException("Table start and end tags are not found in the file ${input.absolutePath}")
+ }
+
+ val newLines = modules.mapNotNull { (moduleName, description) ->
+ if (description == PlatformsDescription.None) {
+ return@mapNotNull null
+ }
+
+ buildString {
+ fun cell(text: String) {
+ appendLine("$text | ")
+ }
+
+ fun writeRecursive(target: PlatformTarget?, topLevel: Boolean): String = buildString {
+ when (target) {
+ null -> append("-")
+
+ is PlatformTarget.LeafTarget -> {
+ append(target.name)
+ }
+
+ is PlatformTarget.Group -> {
+ if (!topLevel) {
+ append(target.name)
+ }
+ append("")
+ target.subtargets.forEach { subtarget ->
+ append("")
+ append(writeRecursive(subtarget, topLevel = false))
+ append("")
+ }
+ append("
")
+ }
+ }
+ }
+
+ appendLine("")
+
+ cell(moduleName)
+
+ when (description) {
+ is PlatformsDescription.JvmOnly -> {
+ cell("Jvm Only")
+ cell("-")
+ cell("-")
+ cell("-")
+ }
+
+ is PlatformsDescription.Kmp -> {
+ cell(writeRecursive(description.platforms[KotlinPlatformType.jvm], topLevel = true))
+ cell(writeRecursive(description.platforms[KotlinPlatformType.js], topLevel = true))
+ cell(writeRecursive(description.platforms[KotlinPlatformType.wasm], topLevel = true))
+ cell(writeRecursive(description.platforms[KotlinPlatformType.native], topLevel = true))
+ }
+
+ is PlatformsDescription.None -> {
+ error("Unexpected None platforms description for module '$moduleName'")
+ }
+ }
+
+ appendLine("
")
+ }
+ }
+
+ output.bufferedWriter(Charsets.UTF_8).use { writer ->
+ original.subList(0, tableStart + 1).forEach { line ->
+ writer.appendLine(line)
+ }
+ newLines.forEach { line ->
+ writer.appendLine(line)
+ }
+ original.subList(tableEnd, original.size).forEach { line ->
+ writer.appendLine(line)
+ }
+ }
+ }
+}
+
+fun Project.registerDumpPlatformTableTask() {
+ tasks.register("dumpPlatformTable") {
+ input.set(PLATFORM_TOPIC_PATH)
+ output.set(PLATFORM_TOPIC_PATH)
+ }
+}
+
+fun Project.registerVerifyPlatformTableTask() {
+ tasks.register("verifyPlatformTable") {
+ val tempFile = Files.createTempFile("platform-table-temp", ".topic").toFile()
+
+ input.set(PLATFORM_TOPIC_PATH)
+ output.set(tempFile)
+
+ doLast {
+ val input = input.get()
+ val output = output.get()
+
+ if (input.readText() != output.readText()) {
+ throw GradleException(
+ "Platform table is not up-to-date. " +
+ "Run `./gradlew dumpPlatformTable --no-configuration-cache` to update it."
+ )
+ }
+ }
+ }
+}
diff --git a/gradle-conventions/src/main/kotlin/conventions-publishing.gradle.kts b/gradle-conventions/src/main/kotlin/conventions-publishing.gradle.kts
index 75bd49792..863f9c8b0 100644
--- a/gradle-conventions/src/main/kotlin/conventions-publishing.gradle.kts
+++ b/gradle-conventions/src/main/kotlin/conventions-publishing.gradle.kts
@@ -2,6 +2,7 @@
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
+import org.gradle.kotlin.dsl.registering
import util.*
val isGradlePlugin = project.name == "gradle-plugin"
@@ -153,8 +154,8 @@ val sonatypeRepositoryUri: String?
return "https://oss.sonatype.org/service/local/staging/deployByRepositoryId/$repositoryId"
}
-fun configureEmptyJavadocArtifact(): org.gradle.jvm.tasks.Jar {
- val javadocJar by project.tasks.creating(Jar::class) {
+fun configureEmptyJavadocArtifact(): TaskProvider {
+ val javadocJar by project.tasks.registering(Jar::class) {
archiveClassifier.set("javadoc")
// contents are deliberately left empty
// https://central.sonatype.org/publish/requirements/#supply-javadoc-and-sources
From 5f992454bf90200b2c03b65b1df0f9a15bf2def2 Mon Sep 17 00:00:00 2001
From: Alexander Sysoev
Date: Mon, 16 Jun 2025 16:34:11 +0200
Subject: [PATCH 5/6] Update some wordings
---
.github/workflows/platforms.yml | 6 +++---
README.md | 10 +++++-----
docs/pages/kotlinx-rpc/topics/platforms.topic | 15 ++++++++++++++-
3 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/platforms.yml b/.github/workflows/platforms.yml
index d1d8269e9..a9082bcd3 100644
--- a/.github/workflows/platforms.yml
+++ b/.github/workflows/platforms.yml
@@ -1,4 +1,4 @@
-name: Check PR Labels
+name: Verify Platforms Table
on:
pull_request:
@@ -8,7 +8,7 @@ permissions:
jobs:
verify-platforms-table:
- name: Verify Platforms Table
+ name: Run Verification
runs-on: ubuntu-latest
steps:
- name: Checkout Sources
@@ -16,4 +16,4 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
- name: Check Platforms Table
- run: ./gradlew verifyPlatformsTable --no-configuration-cache
+ run: ./gradlew verifyPlatformTable --no-configuration-cache
diff --git a/README.md b/README.md
index 5fd2383ef..7732af789 100644
--- a/README.md
+++ b/README.md
@@ -114,11 +114,11 @@ However, we are also a multi-module library, meaning that some modules may not s
Current high-level status:
-| Subsystem | Supported Platforms |
-|-----------|--------------------------------------------------|
-| Core | Jvm, Js, WasmJs, WasmWasi, Apple, Linux, Windows |
-| kRPC | Jvm, Js, WasmJs, Apple, Linux, Windows |
-| gRPC | Jvm (in Jvm-only projects) |
+| Subsystem | Supported Platforms | Notes |
+|-----------|--------------------------------------------------|---------------------------------------------------------------------------------------------|
+| Core | Jvm, Js, WasmJs, WasmWasi, Apple, Linux, Windows | |
+| kRPC | Jvm, Js, WasmJs, Apple, Linux, Windows | WasmWasi is blocked by [kotlin-logging](https://github.com/oshai/kotlin-logging/issues/433) |
+| gRPC | Jvm | Projects with `kotlin("jvm")` **only**!
KMP support is in development |
For more detailed module by module information,
check out our [platform support table](https://kotlin.github.io/kotlinx-rpc/platforms.html).
diff --git a/docs/pages/kotlinx-rpc/topics/platforms.topic b/docs/pages/kotlinx-rpc/topics/platforms.topic
index 30b4c832b..1511fbaaa 100644
--- a/docs/pages/kotlinx-rpc/topics/platforms.topic
+++ b/docs/pages/kotlinx-rpc/topics/platforms.topic
@@ -18,18 +18,31 @@
Subsystem |
Supported Platforms |
+ Notes |
Core |
Jvm, Js, WasmJs, WasmWasi, Apple, Linux, Windows |
+ |
kRPC |
Jvm, Js, WasmJs, Apple, Linux, Windows |
+
+ WasmWasi is blocked by kotlin-logging.
+ |
gRPC |
- Jvm (in Jvm-only projects) |
+ Jvm |
+
+
+ Projects with kotlin("jvm") only!
+
+
+ KMP support is in development
+
+ |
From 29358886fbfebd8c1aeca61f8374345a2f269e84 Mon Sep 17 00:00:00 2001
From: Alexander Sysoev
Date: Mon, 16 Jun 2025 16:37:52 +0200
Subject: [PATCH 6/6] Removed some old docs
---
.../topics/annotation-type-safety.topic | 4 ++--
docs/pages/kotlinx-rpc/topics/krpc-ktor.topic | 2 +-
docs/pages/kotlinx-rpc/topics/strict-mode.topic | 14 +++++++-------
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/docs/pages/kotlinx-rpc/topics/annotation-type-safety.topic b/docs/pages/kotlinx-rpc/topics/annotation-type-safety.topic
index be8df1ed2..75888d109 100644
--- a/docs/pages/kotlinx-rpc/topics/annotation-type-safety.topic
+++ b/docs/pages/kotlinx-rpc/topics/annotation-type-safety.topic
@@ -10,11 +10,11 @@
@Rpc
- interface MyService : RemoteService
+ interface MyService
class MyServiceImpl : MyService
- fun <T : RemoteService> withService() {}
+ fun <T> withService() {}
The compiler can't guarantee that the passed type parameter is the one for which the code generation was run:
diff --git a/docs/pages/kotlinx-rpc/topics/krpc-ktor.topic b/docs/pages/kotlinx-rpc/topics/krpc-ktor.topic
index d747c4056..e28e765ee 100644
--- a/docs/pages/kotlinx-rpc/topics/krpc-ktor.topic
+++ b/docs/pages/kotlinx-rpc/topics/krpc-ktor.topic
@@ -87,7 +87,7 @@
)
@Rpc
- interface ImageService : RemoteService {
+ interface ImageService {
suspend fun processImage(url: String): ProcessedImage
}
diff --git a/docs/pages/kotlinx-rpc/topics/strict-mode.topic b/docs/pages/kotlinx-rpc/topics/strict-mode.topic
index 33e660682..8c3112a09 100644
--- a/docs/pages/kotlinx-rpc/topics/strict-mode.topic
+++ b/docs/pages/kotlinx-rpc/topics/strict-mode.topic
@@ -20,7 +20,7 @@
Deprecation level: ERROR
@Rpc
- interface Service : RemoteService {
+ interface Service {
suspend fun old(): StateFlow<Int> // deprecated
suspend fun new(): Flow<Int> // use .stateIn on the client side
@@ -32,7 +32,7 @@
Deprecation level: ERROR
@Rpc
- interface Service : RemoteService {
+ interface Service {
val old: Flow<Int> // deprecated
suspend fun new(): Flow<Int> // store flow locally
@@ -43,7 +43,7 @@
Deprecation level: ERROR
@Rpc
- interface Service : RemoteService {
+ interface Service {
suspend fun old(): Flow<Flow<Int>> // deprecated
// no particular alternative, depends on the use case
@@ -57,7 +57,7 @@
data class SpotifyWrapped(val myMusicFlow: Flow<Rap>, val extra: Data)
@Rpc
- interface Service : RemoteService {
+ interface Service {
suspend fun old(): SpotifyWrapped // deprecated
// one should consider message delivery order when calling these
@@ -73,7 +73,7 @@
data class SpotifyWrapped(val extra: Data)
@Rpc
- interface Service : RemoteService {
+ interface Service {
suspend fun old(): Flow<SpotifyWrapped> // deprecated
fun new(): Flow<SpotifyWrapped>
@@ -102,7 +102,7 @@
@Rpc
- interface Service : RemoteService {
+ interface Service {
suspend fun oldClient(flow: Flow<Int>)
suspend fun oldServer(): Flow<Int>
}
@@ -122,7 +122,7 @@
@Rpc
- interface Service : RemoteService {
+ interface Service {
suspend fun newClient(flow: Flow<Int>)
fun newServer(): Flow<Int>
}