kotlin-tooling-native-build-performance

Par kotlin · kotlin-agent-skills

Diagnostique et corrige la compilation et l'édition de liens Kotlin/Native lentes dans les projets Kotlin Multiplatform ciblant iOS. À utiliser lorsque l'utilisateur signale des builds iOS ou shared-framework lents, des tâches `linkDebug*`/`linkRelease*` ou XCFramework longues, des builds CI à froid qui re-téléchargent la toolchain Kotlin/Native, du code généré par KSP ou d'autres outils sur le chemin natif, l'utilisation de `transitiveExport`, ou demande un plan d'optimisation des performances de build distinguant développement local et CI.

npx skills add https://github.com/kotlin/kotlin-agent-skills --skill kotlin-tooling-native-build-performance

Performance des builds Kotlin/Native

Transformez « le build iOS est lent » en un diagnostic mesuré et un petit ensemble de correctifs sûrs. Deux règles s'appliquent partout :

  1. Ne sacrifiez jamais le comportement de release requis. Une boucle locale plus rapide ne doit pas changer ce que CI publie.
  2. Mesurez avant et après avec la même commande et le même état du build. Un correctif non mesuré n'est qu'une supposition.

Étape 0 : Classifier le scénario lent

Établissez quatre faits avant de modifier quoi que ce soit : (local ou CI), quoi (boucle de debug ou artefact release/distribution), état (premier build, clean, warm, ou no-op), et phase (quelles tâches dominent le log). Ensuite, associez le symptôme dominant :

Symptôme dans le log du build Cause probable Consulter
Tâches linkRelease* ou *ReleaseXCFramework dans une boucle de développement local Construction d'artefacts de distribution pour le développement artifacts-and-targets
Distribution Kotlin/Native compiler téléchargée à chaque exécution CI ~/.konan non préservé entre les exécutions caching-and-gradle
Longue pause avant le démarrage de la première tâche Phase de configuration, pas de configuration cache caching-and-gradle
Tous les targets iOS se construisent quand un seul simulator est nécessaire Tâche large (build, assemble, assemble*XCFramework) ou targets inutilisés artifacts-and-targets
Tâches ksp* avant compileKotlinIos* Travail de code généré sur le chemin natif exports-and-generated-code
La modification d'une petite source recompile et relie tout Caches compilateur désactivés, ou incrementality manquante caching-and-gradle, experimental
Machine surchargée pendant que plusieurs tâches link* s'exécutent à la fois Linking natif parallèle caching-and-gradle, caveat worker-limit

Étape 1 : Audit et mesure

  1. Exécutez l'audit statique depuis la racine du projet :

    scripts/audit-native-build.sh /path/to/project

    C'est en lecture seule et affiche les trouvailles file:line (caches désactivés, tâches locales larges, transitiveExport, large configuration KSP, cache CI .konan manquant), chacune pointant vers le fichier de référence avec le correctif. Les trouvailles sont des indices, non des verdicts — confirmez chacun par rapport à la politique du projet.

  2. Trouvez la commande que l'utilisateur attend réellement : un script, une étape CI, ou l'invocation Gradle à l'intérieur d'une phase de build Xcode. Optimisez cette commande, pas une tâche que vous avez choisie vous-même.

  3. Exécutez-la deux fois si possible. Le premier build télécharge les composants Kotlin/Native et remplit les caches ; seuls les deuxième et les suivants sont représentatifs. Attribuez le temps par tâche avant de blâmer le compilateur :

    kotlin.build.report.output=file   # écrit dans build/reports/kotlin-build/

    Le --scan ou --profile de Gradle fonctionnent aussi.

  4. Si vous ne pouvez pas exécuter le build (pas d'hôte macOS, pas de Xcode), analysez les logs, les build scans, ou les métriques archivées à la place — et déclarez explicitement que la conclusion est statique.

Étape 2 : Corriger dans un ordre sûr

Appliquez les correctifs un à la fois, en remesure au fur et à mesure :

  1. Restaurer les défauts sains — supprimer les contournements cache/daemon, activer les caches Gradle build et configuration, garder ~/.konan warm dans CI, mettre à jour Kotlin : references/caching-and-gradle.md
  2. Construire seulement ce dont la boucle de feedback a besoin — une tâche spécifique par boucle, méthode d'intégration correcte, matrice de targets justifiée : references/artifacts-and-targets.md
  3. Réduire le coût de l'export et du code généré — supprimer transitiveExport, réduire export(...), limiter le travail KSP aux compilations native qui en ont besoin : references/exports-and-generated-code.md
  4. Commutateurs expérimentaux en dernier, avec l'accord de l'utilisateur : references/experimental.md

Exemple travaillé

Un développeur sur un Mac Apple Silicon se plaint que « chaque changement de module partagé coûte 12 minutes ». Sa boucle exécute ./gradlew :shared:assembleXCFramework. Un build scan de la deuxième exécution (warm) affiche :

:shared:linkReleaseFrameworkIosArm64             348s
:shared:linkReleaseFrameworkIosX64               341s
:shared:compileKotlinIosX64                       96s
:shared:linkDebugFrameworkIosSimulatorArm64       41s
:shared:compileKotlinIosSimulatorArm64            38s
configuration phase                               64s

Chaîne de raisonnement :

  • La boucle est local + debug + warm, mais ~690s vont à linkRelease* — le linking de release est d'un ordre de grandeur plus lent que debug et seule CI en a besoin. Remplacez la commande locale par :shared:linkDebugFrameworkIosSimulatorArm64 (ou la tâche d'embed Xcode si Xcode pilote le build). (artifacts-and-targets)
  • Tout le travail iosX64 sert les simulateurs Intel ; demandez si l'équipe les supporte toujours avant de supprimer le target. (artifacts-and-targets)
  • 64s de configuration à chaque exécution disparaissent derrière org.gradle.configuration-cache=true une fois testé. (caching-and-gradle)
  • Boucle attendue après le changement : ~40s compile + ~40s link sur les builds warm — confirmez en réexécutant la nouvelle commande deux fois et en comparant.
  • CI garde assembleXCFramework intact ; notez-le explicitement dans le rapport.

Vérifier

  • [ ] Réexécutez la commande de baseline exacte ; comparez le build warm contre warm, pas warm contre cold.
  • [ ] La deuxième exécution avec le configuration cache signale qu'il est réutilisé.
  • [ ] Le log de développement local ne contient plus linkRelease*, *ReleaseXCFramework, ou les tâches générateur supprimées.
  • [ ] CI produit toujours chaque artefact release requis, inchangé.
  • [ ] Les tests passent et l'app s'exécute toujours depuis Xcode.
  • [ ] scripts/audit-native-build.sh ne signale aucune trouvaille que vous n'avez pas consciemment acceptée et documentée.

Rapportez vos changements

Terminez par une brève note de performance :

  • Le scénario lent (local/CI, debug/release, cold/warm) et la preuve mesurée — ou une déclaration que l'analyse était statique.
  • Chaque changement, et pourquoi il est sûr pour le comportement de release.
  • Les commandes avant/après que l'utilisateur peut exécuter pour confirmer le gain.
  • Compromis restants : drapeaux expérimentaux activés, targets supprimés sous une hypothèse de politique, limites worker, ou travail de code généré différé.
  • Liens vers la documentation officielle pertinente ci-dessous.

Documentation officielle

Sujet Lien
Improving Kotlin/Native compilation time https://kotlinlang.org/docs/native-improving-compilation-time.html
Kotlin Gradle plugin compilation and caches https://kotlinlang.org/docs/gradle-compilation-and-caches.html
iOS integration methods https://kotlinlang.org/docs/multiplatform-ios-integration-overview.html
Direct integration with Xcode https://kotlinlang.org/docs/multiplatform/multiplatform-direct-integration.html
Building final native binaries and XCFrameworks https://kotlinlang.org/docs/multiplatform/multiplatform-build-native-binaries.html
Kotlin/Native binary options https://kotlinlang.org/docs/native-binary-options.html
KSP with Kotlin Multiplatform https://kotlinlang.org/docs/ksp-multiplatform.html

Skills similaires