Le nouveau schéma de compilation séparée de Kotlin aligne les builds multiplateformes sur l'IDE
Public- 28 Sep, 2026

L'approche actuelle de compilation de Kotlin Multiplatform fonctionne, mais peut produire un comportement inattendu et difficile à prévoir. Le cœur du problème est un désaccord entre l'IDE et le compilateur : ils résolvent différemment les appels depuis les source sets communs vers les déclarations des dépendances. Dans Kotlin 2.5.0-Beta1, JetBrains a ajouté une « compilation séparée » optionnelle censée corriger cela — aligner le résultat de la compilation sur l'analyse de l'IDE et pointer plus précisément vers les appels problématiques depuis les source sets communs vers le code des bibliothèques. En prime, le schéma active aussi la compilation incrémentale pour les source sets communs.
Le problème trouve ses racines dans la structure d'un module KMP. Un module avec du code commun contient généralement plusieurs source sets : un commun (commonMain) et des source sets pour des plateformes spécifiques (jvmMain pour Kotlin/JVM). Pendant la compilation d'un source set de plateforme, le code de jvmMain plus tous les source sets communs associés est compilé contre les artefacts de plateforme des dépendances. De ce fait, le code de commonMain a la possibilité de se résoudre implicitement vers une déclaration de jvmMain dans une dépendance — précisément ce qu'IntelliJ IDEA interdit. Comme les déclarations de jvmMain ne figurent pas dans les métadonnées KLIB, l'IDE affiche pour ces appels une erreur « unresolved reference », tandis que le compilateur les accepte silencieusement et le code se compile sans erreur.

L'activation de la compilation séparée amène le compilateur à se comporter de manière plus stricte, en alignant son comportement sur celui de l'IDE. L'indicateur optionnel s'ajoute dans gradle.properties sous la forme kotlin.kmp.separateCompilation=true, et la fonctionnalité est désactivée par défaut car elle est Experimental. Une fois l'option activée, le code qui se compilait auparavant échoue désormais : par exemple, l'appel à Foo depuis app/commonMain, lorsque class Foo est déclarée uniquement dans lib/jvmMain, devient une erreur de compilation et non un simple avertissement dans l'IDE. La correction consiste à établir une connexion explicite via expect/actual : déclarer expect class Foo dans lib/commonMain et marquer la version de plateforme comme actual class Foo. La même règle s'applique aux ensembles de tests communs commonTest, car les tests « dépendent » du code principal ; un commonTest compilé contre jvmMain ne peut plus atteindre les déclarations de plateforme sans un expect correspondant dans commonMain.
Le schéma élimine également les écarts lors du choix de la surcharge. Lorsque plusieurs surcharges existent dans lib/commonMain et lib/jvmMain, l'IDE et le compilateur choisissent actuellement des déclarations différentes. Par exemple, avec fun foo(x: Any) dans commonMain et fun foo(x: String) dans jvmMain, l'IDE résout foo("") vers la surcharge commune Any, mais la compilation choisit la surcharge la plus spécifique String, et à l'exécution « platform » est imprimé. Avec la compilation séparée, l'appel se résout vers la déclaration commune, et « common » est imprimé, ce qui correspond au comportement de l'IDE. Un échec plus subtil apparaît lorsque l'erreur ne se manifeste que dans le code de plateforme : si les classes actual ajoutent des supertypes que leurs équivalents expect n'ont pas, l'inférence du type de retour peut, sur la JVM, se réduire à Any et casser l'accès à .name, provoquant des échecs de compilation uniquement sur la JVM.

Avec la compilation séparée, app/commonMain résout les appels uniquement par rapport aux déclarations d'eventsLib/commonMain, si bien que le compilateur déduit le bon type de retour Event, et la compilation pour la JVM se termine proprement. JetBrains documente les problèmes connus encore en cours de correction. L'essentiel : pour que la compilation séparée fonctionne correctement, les auteurs de bibliothèques doivent publier des métadonnées KLIB — c'est déjà le comportement par défaut des tâches de publication du plugin Gradle KMP, mais le nouveau schéma rend ces KLIB indispensables. La fonctionnalité étant expérimentale, attendez-vous à des vérifications plus strictes à la compilation et prévoyez d'adapter en conséquence le code existant.
