Kotlin K2 y generador de fuente independiente

Publicado por Ting-Yuan Huang – Ingeniero de software y Jiaxiang Chen – Ingeniero de software

La herramienta Kotlin Symbol Processing (KSP) proporciona una API de alto nivel para realizar metaprogramación en Kotlin. Se han creado muchas herramientas sobre KSP, lo que permite generar código Kotlin en tiempo de compilación. Por ejemplo, Jetpack Room utiliza KSP para generar código para acceder a la base de datos, basado en una interfaz proporcionada por el desarrollador, como por ejemplo:

@Dao interfaz UserDao { @Query(“SELECT * FROM user”) fun getAll(): Lista }

KSP proporciona la API al código Kotlin para que Room, en este caso, pueda generar la implementación real de esa interfaz. Aunque KSP se ha convertido en una base fundamental para la metaprogramación en Kotlin, su implementación actual tiene algunas deficiencias que pretendemos abordar con una nueva arquitectura KSP2. Este blog detalla los cambios arquitectónicos y el impacto de los complementos basados ​​en KSP.

Además, KSP2 tiene soporte preliminar para:

    • El nuevo compilador de Kotlin (nombre en clave K2)
    • Un nuevo generador de código fuente independiente que ofrece más flexibilidad y funcionalidad que el complemento del compilador Kotlin actual.

Después de recibir comentarios sobre la nueva arquitectura y continuar abordando las brechas, trabajaremos para lanzar KSP 2.0 en el que estos cambios serán predeterminados.

Habilitar la vista previa de KSP2

Los nuevos cambios de vista previa se pueden habilitar en KSP 1.0.14 o posterior usando una marca en gradle.properties:

Nota: Es posible que deba aumentar el tamaño del montón del demonio Gradle ahora que KSP y los procesadores se ejecutan en el demonio Gradle en lugar del demonio del compilador Kotlin (que tiene un tamaño de montón predeterminado mayor), por ejemplo org.gradle.jvmargs=-Xmx4096M -XX : Tamaño máximo Metaspazio = 1024 m

KSP2 y K2

Internamente, KSP2 utiliza el compilador Beta Kotlin K2 (que será el compilador predeterminado en Kotlin 2.0). Puede usar KSP2 antes de cambiar el compilador Kotlin a K2 (a través de la configuración LanguageVersion), pero si desea usar K2 para compilar su código, consulte: Pruebe el compilador K2 en sus proyectos de Android.

Generador de fuente independiente

KSP1 se implementa como un complemento del compilador Kotlin 1.x. Para ejecutar KSP es necesario ejecutar el compilador y especificar KSP y las opciones de complemento. En Gradle, las tareas KSP son tareas de compilación personalizadas que envían el trabajo real a KotlinCompileDaemon de forma predeterminada. Esto dificulta un poco la depuración y las pruebas, porque KotlinCompileDaemon se ejecuta en su propio proceso, fuera de Gradle.

En KSP2, la implementación puede considerarse como una biblioteca con un punto de entrada principal. Los sistemas y herramientas de compilación pueden llamar a KSP con este punto de entrada, sin configurar el compilador. Esto hace que sea muy fácil llamar a KSP mediante programación y es muy útil especialmente para depurar y probar. Con KSP2 puede establecer puntos de interrupción en los procesadores KSP sin tener que realizar otras tareas de configuración irregulares para permitir la depuración.

Todo se vuelve mucho más fácil porque KSP2 ahora controla su ciclo de vida y puede llamarse como un programa independiente o mediante programación, como:

val kspConfig = KSPJvmConfig.Builder().apply { // Toda la configuración ocurre aquí. }.build() val exitCode = KotlinSymbolProcessing(kspConfig, listOfProcessors, kspLoggerImpl).execute()

Cambios en el comportamiento de la API KSP2

Con la nueva implementación, también es una gran oportunidad para introducir algunas mejoras en el comportamiento de la API para que los desarrolladores que confían en KSP sean más productivos y tengan más posibilidades de depuración y recuperación de errores. Por ejemplo, al resolver Map, KSP1 simplemente devuelve un tipo de error. En KSP2, se devolverá el mapa.. Aquí hay una lista de los cambios actuales en el comportamiento de la API que planeamos realizar en KSP2:

  1. Resuelva el tipo implícito de la llamada a la función: val error = mutableMapOf()

    KSP1: Todo el tipo será un tipo de error debido a una resolución de tipo fallida.

    KSP2: Resolverá con éxito el tipo de contenedor y, para el tipo inexistente en el argumento de tipo, informará correctamente los errores en el argumento de tipo específico.

  2. Parámetro de tipo ilimitado

    KSP1: Sin límite

    KSP2: ¿Un límite superior de Any? siempre se inserta para mantener la coherencia

  3. Resolver referencias de alias de tipo en tipos de funciones y anotaciones

    KSP1: Ampliado al tipo subyacente, sin alias

    KSP2: No ampliado, como usos en otros lugares.

  4. Nombres completos

    KSP1: Los constructores tienen FQN si provienen de la fuente, pero no si provienen de una biblioteca.

    KSP2: Los fabricantes no tienen FQN

  5. Escriba argumentos de tipo interno

    KSP1: Los tipos internos toman argumentos de tipos externos.

    KSP2: Los tipos internos no toman argumentos de tipos externos.

  6. Tipo de temas de proyecciones estelares

    KSP1: Las proyecciones estelares tienen argumentos de tipo que se expanden a variaciones reales basadas en los sitios de declaración.

    KSP2: Sin expansión. Las proyecciones estelares tienen valores nulos en sus argumentos de tipo.

  7. variación de la matriz de Java

    KSP1: Java Array tiene un límite superior invariante

    KSP2: Java Array tiene un límite superior covariante

  8. Entradas de enumeración

    KSP1: Una entrada de enumeración tiene su propio subtipo con un supertipo de la clase de enumeración (comportamiento lingüísticamente incorrecto)

    KSP2: El tipo de entrada de enumeración es el tipo de clase de enumeración adjunta.

  9. Escenario de anulación múltiple

    Por ejemplo

    interfaz GrandBaseInterface1 { fun foo(): Unidad } interfaz GrandBaseInterface2 { fun foo(): Unidad } interfaz BaseInterface1 : GrandBaseInterface1 { } interfaz BaseInterface2 : GrandBaseInterface2 { } clase OverrideOrder1 : BaseInterface1, GrandBaseInterface2 { override fun foo() = TODO() } clase OverrideOrder2: BaseInterface2, GrandBaseInterface1 { anular diversión foo() = TODO() }

    KSP1:

    Busque símbolos anulados en orden BFS; se devuelve el primer supertipo encontrado en la lista directa de supertipos que contiene el símbolo anulado. Por ejemplo, KSP dirá que OverrideOrder1.foo() anula GrandBaseInterface2.foo() y OverrideOrder2.foo() anula GrandBaseInterface1.foo()

    KSP2:

    En orden DFS, se devuelve el primer supertipo encontrado con símbolos sobrescritos (con búsqueda recursiva de supertipos) en la lista directa de supertipos.

    Por ejemplo, KSP dirá que OverrideOrder1.foo() anula GrandBaseInterface1.foo() y OverrideOrder2.foo() anula GrandBaseInterface2.foo()

  10. modificador de java

    KSP1: Los campos transitorios/volátiles son firmes de forma predeterminada

    KSP2: Los campos transitorios/volátiles están abiertos de forma predeterminada

  11. Escriba anotaciones

    KSP1: Las anotaciones de tipo en un argumento de tipo se reflejan solo en el símbolo del argumento de tipo.

    KSP2: Las anotaciones de tipo en un argumento de tipo ahora también están presentes en el tipo resuelto

  12. parámetros vararg.

    KSP1: Considerado un tipo de matriz

    KSP2: No se considera un tipo de matriz

  13. Miembros sintetizados de Enums

    KSP1: Faltan valores y valueOf si la enumeración está definida en fuentes de Kotlin

    KSP2: los valores y valueOf están siempre presentes

  14. Miembros sintetizados de clases de datos.

    KSP1: Faltan el componente N y la copia si la clase de datos está definida en las fuentes de Kotlin

    KSP2: componenteN y copia siempre están presentes

Nuevo esquema de procesamiento multiplataforma

En cuanto al esquema de procesamiento, es decir, qué fuentes se procesan y cuándo, el principio de KSP es ser coherente con el esquema de compilación existente de la compilación. En otras palabras, lo que ve el compilador es lo que ven los procesadores, más el código fuente generado por los procesadores.

Que ven los procesadores

Compilador de Kotlin ver
ClassA.kt, UtilB.kt, InterfaceC.kt … ClassA.kt, UtilB.kt, InterfaceC.kt … + GeneratedFromA.kt, …

En el esquema de compilación KSP1 actual, los conjuntos de fuentes comunes/compartidos se procesan y compilan varias veces, con cada destino. Por ejemplo, commonMain se procesa y compila 3 veces en el siguiente diseño del proyecto. Poder procesar todas las fuentes de las dependencias es conveniente con una excepción: los procesadores no ven las fuentes generadas por commonMain cuando procesan jvmMain y jsMain. Hay que reelaborar todo y eso puede resultar ineficiente.

Diagrama de flujo que ilustra las fuentes generadas por el procesamiento jvmMain y jsMain en comúnMain

asignaciones

aporte

salir

kspKotlinCommonMainMetadatos

comúnPrincipal

generadoComuna

kspKotlinJvm

comúnMain, jvmMain

generadoCommonJvm

kspKotlinJs

comúnMain, jsMain

generadoCommonJs

compilarKotlinCommonMainMetadata

commonaPrincipal, generadoComún

común.klib

compilarKotlinJvm

commonMain, jvmMain, generadoCommonJvm

aplicación.jar

compilarKotlinJs

commonMain, jsMain, generadoCommonJs

principal.js

En KSP2, planeamos agregar un modo experimental que intenta alinearse con cómo se compilan los conjuntos de fuentes en K2 Mejor. Todas las fuentes se pueden procesar solo una vez con el nuevo esquema de procesamiento disponible:

asignaciones

aporte

salir

Soluble pero no disponible en

obtener todos los archivos /

obtener símbolos con anotación

kspKotlinCommonMainMetadatos

comúnPrincipal

generadoComuna

kspKotlinJvm

jvmPrincipal

generadoJvm

comúnPrincipal, generadoComún

kspKotlinJs

jsPrincipal

Js generados

commonaPrincipal, generadoComún

compilarKotlinCommonMainMetadata

commonaPrincipal, generadoComún

común.klib

compilarKotlinJvm

comúnMain, jvmMain, generadoComún, generadoJvm

aplicación.jar

compilarKotlinJs

commonMain, jsMain, generadoCommon, generadoJs

principal.js

Tenga en cuenta que Kotlin 2.0 todavía está en versión beta y el modelo de compilación está sujeto a cambios. Háganos saber cómo funciona para usted y háganoslo saber. comentario.

Comentarios sobre la vista previa de KSP2

KSP2 está en vista previa pero hay aún más Trabajo por hacer antes de un lanzamiento estable. ¡Esperamos que estas nuevas funciones le ayuden a ser más productivo al utilizar KSP! Por favor proporcionanos el tuyo comentario para que podamos hacer que estas mejoras sean extraordinarias a medida que avancen hacia la estabilidad.

Compruebe también

en vivo desde Droidcon, incluida la mayor actualización de Gemini en Android Studio y más lanzamientos del SDK de Android.

Acabamos de lanzar nuestro episodio de otoño de #TheAndroidShow en YouTube etcétera desarrollador.android.comy esta vez …

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *