Use Gradle sub-projects with Kotlin multiplatform

This took a crazy amount of time, so I hope this is useful for someone!

There is a functional example on Github: kotlin_multiplatform_gradle_demo

Several sources helped, but a lot of it was trial and error, so if something is bad practise, please let me know!


For the minimal example, the structure is like this:

├── alpha
│   ├── alpha-js
│   │   └── build.gradle
│   ├── alpha-jvm
│   │   └── build.gradle
│   ├── build.gradle
│   └── src
│       └── main
│           ├── kotlin
│           │   └── demo
│           │       └── alpha
│           │           └── main.kt
├── beta
│   ├── beta-js
│   │   ├── build.gradle
│   │   └── src
│   │       └── main
│   │           └── kotlin
│   │               └── demo
│   │                   └── beta
│   │                       └── platform.kt
│   ├── beta-jvm
│   │   ├── build.gradle
│   │   └── src
│   │       └── main
│   │           └── kotlin
│   │               └── demo
│   │                   └── beta
│   │                       └── platform.kt
│   ├── build.gradle
│   └── src
│       └── main
│           └── kotlin
│               └── demo
│                   └── beta
│                       └── platform.kt
├── build.gradle
└── settings.gradle

The common modules (alpha and beta) need platform modules for each platform with at least a `build.gradle``.

The settings.gradle file imports all modules, including platform ones.

Dependencies, e.g. from alpha on beta, is declared in the common alpha module and all alpha platform modules.


Some patterns I learned:

  • Every 'normal' (common) module has one platform module for each platform.
  • For common module alpha, the javascript platform module must be called alpha-js (similar for -jvm).
  • If there is no platform specific code, this module can be just a gradle file in a directory.
  • The platform modules can be conveniently placed inside of the common module directory (so alpha:alpha-js).
  • The common module should not refer to the platform modules; the platform modules have a dependency expectedBy project(":the_common_module").
  • If module alpha depends on beta, then

    • alpha must have dependencies { compile project(":beta") }
    • alpha-js must have dependencies { compile project(":beta:beta-js") } (in addition to expectedBy)
    • alpha-jvm must have dependencies { compile project(":beta:beta-jvm") } (in addition to expectedBy) etc
  • Only the top module has settings.gradle, which includes ALL submodules (including platform ones).

  • Make sure to get the names right, as incorrect ones don't cause an error, they just fail silently. (It seems ridiculous but I guess there is a reason.)
  • Do NOT put all the output into a single, shared build directory - this results in several weird non-deterministic errors.

I used to have the full config files here, but it's better to just check the code on Github because it's really long.