Guía — kmapx en Kotlin Multiplatform¶
kmapx es multiplataforma de verdad: las clases anotadas viven en commonMain, y el processor
genera una función por target con semántica idéntica. El output es Kotlin puro — sin
reflection y sin APIs java.* (hay un test de contrato que lo garantiza) — así que el mismo
mapeo funciona en JVM, Android, JS, Wasm y nativo.
Cómo funciona la generación por target¶
KSP no corre "una vez para common": corre una vez por cada target (kspKotlinJvm,
kspKotlinJs, kspKotlinLinuxX64, …) y el .kt generado aterriza en el source set generado
de ese target:
build/generated/ksp/
├── jvm/jvmMain/kotlin/…/PersonMappings.kt
├── js/jsMain/kotlin/…/PersonMappings.kt
└── linuxX64/linuxX64Main/kotlin/…/PersonMappings.kt
Las tres funciones son idénticas en comportamiento. Tu código común NO ve la función generada
(no existe en commonMain), pero tus tests en commonTest sí — porque commonTest compila
por target contra el código generado de cada uno. Esa es la consecuencia práctica más
importante: escribe los tests de mapeo en commonTest y la misma suite corre en JVM, Node
y nativo.
Configuración copiable¶
// build.gradle.kts
plugins {
kotlin("multiplatform") version "2.1.21"
id("com.google.devtools.ksp") version "2.1.21-2.0.1"
}
kotlin {
jvm(); js(IR) { nodejs() }; linuxX64() // + los targets que necesites
sourceSets {
commonMain {
dependencies {
implementation("io.github.kuroxbyte:kmapx-annotations:0.1.0")
// solo si usas Converts<A, B> o Patch<T>:
implementation("io.github.kuroxbyte:kmapx-runtime:0.1.0")
}
}
commonTest { dependencies { implementation(kotlin("test")) } }
}
}
// KSP se declara POR TARGET — un "ksp(...)" a secas es la configuración de JVM puro
// y en un proyecto multiplatform no engancha nada:
dependencies {
add("kspJvm", "io.github.kuroxbyte:kmapx-frontend-ksp:0.1.0")
add("kspJs", "io.github.kuroxbyte:kmapx-frontend-ksp:0.1.0")
add("kspLinuxX64", "io.github.kuroxbyte:kmapx-frontend-ksp:0.1.0")
// Apple: add("kspIosSimulatorArm64", ...) etc. — requiere host macOS con Xcode
}
# gradle.properties
ksp.useKSP2=true
Matriz de targets de annotations y runtime (v1)¶
| Target | Nota |
|---|---|
| JVM | Android consume este artefacto — la librería no tiene dependencias de plataforma |
| JS (IR) | browser y nodejs |
| Wasm (JS) | |
| Linux x64 | |
| Windows x64 (mingw) | |
| macOS x64 / arm64 | |
| iOS arm64 / simulatorArm64 |
El processor (kmapx-frontend-ksp) es JVM-only: corre dentro del build de Gradle y no
viaja a tus targets — por eso no necesita (ni tiene) variantes nativas.
Trampas conocidas (aprendidas con tests, no con fe)¶
- Kotlin/Native rechaza
()y,en nombres de test con backticks. Un test comúnfun `mapea X (caso Y)`()compila en JVM/JS y revienta encompileTestKotlin<Native>con un error críptico. Si tu suite corre en nativo, evita paréntesis y comas en los nombres. - Linkear binarios Apple exige Xcode completo. Con solo Command Line Tools se compilan
los klibs pero el link de los test runners falla. En CI, separa los targets Apple a un job
macOS con Xcode (en este repo se gatean con
-Pkmapx.ci.apple=true). expect classanotada →KMX025. El mapeo de declaracionesexpect/actuales no-goal en v1: KSP procesa por target y la identidad de la clase difiere entre ellos. Anota laactualde cada target, o —mejor— mapea una clase común concreta.- Los tests nativos solo EJECUTAN en su host. Linux en CI Linux, Apple en CI macOS; en los demás hosts solo cross-compilan. Si tu CI corre un único sistema operativo, estás compilando — no probando — la otra mitad de la matriz.
- El código generado no es una API de
commonMain. Si necesitas exponer un mapeo al código común, envuélvelo en unaexpect fun/interfaz tuya por target — o replantéate si el mapeo pertenece a la capa común.