Please be aware that this was created in early 2018. Some of it may still be useful, but please realize that parts will have stopped working or become deprecated. I am no longer updating it (though PRs are welcome).
This project is an example of one way to set up a multi-platform Kotlin project separated into Gradle submodules.
The code itself is super simple, with just a platform-dependent method (expect/actual).
To run the code::
gradle wrapper
./gradlew run
Or to run only one platform (jvm
in this example)::
./gradlew -p alpha/alpha-jvm run
This should show (between a bunch of Gradle stuff)::
Hello from JVM
Hello from JS
To collect the Javascript files in build/js
, use the collectWeb
task.
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
) etcOnly 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.)
Just because the build completes and creates jars does not mean it worked; the jar might only contain .kjsm and .kotlin_metadata files.
This demo uses the top level build.gradle
for coordinating submodules; the top level doesn't contain code or platforms.
It's not hard to put shared functionality per level together at the top level (except buildscript
which is inherited), possibly with one gradle file per platform.
If you don't mind using string manipulation and adhering to a naming scheme (you have to anyway), you can specify the dependencies in dependencies.gradle
and not repeat them for every platform.
Could not find method expectedBy() for arguments ...
, move the dependencies
block lower in the file.package
statement, and check all the above..npm
directory for your system is writable.e: No class roots are found in the JDK path: /usr/lib/jvm/java-9-openjdk-amd64
or similar, set JAVA_HOME
environment variable to where java 8 jdk is (for example /usr/lib/jvm/java-8-openjdk-amd64/
).TypeError: Cannot read property 'config' of undefined
, probably qunit did not see your test file. Maybe there are no tests (should be caught by Gradle) or there is something wrong with the pattern (absolute paths don't work, for example).Error: Cannot find module
on JS tests, set NODE_PATH
to the js dir, because imports aren't relative to the file of the current dir but only to path & node modules.java.lang.NoClassDefFoundError
, this happens because of shared build dir (doing a clean build works too, but not a long-term solution). Adding hamcrest to dependencies does not work.build
, gradle
, .gradle
, gradlew
, gradlew.bat
and try again... (Yes, sage advice).alpha:js
instead of alpha:alpha-js
(I tried but they couldn't see each other).w: Module "[...]-js" is defined in more than one file
which is shown for all js modules.w: Classpath entry points to a non-existent location: /home/mark/gradle_demo/alpha/build/classes/java/main
.Currently the tests just use kotlin.test
, and are ran by JUnit
on JVM and QUnit
in Javascript. They are included in ./gradlew run
.
Inspiration from:
These paragraphs from the documentation may be useful:
A multiplatform project consists of three types of modules:
* A common module contains code that is not specific to any platform, as well as declarations without implementation of platform-dependent APIs. Those declarations allow common code to depend on platform-specific implementations.
* A platform module contains implementations of platform-dependent declarations in the common module for a specific platform, as well as other platform-dependent code. A platform module is always an implementation of a single common module.
* A regular module. Such modules target a specific platform and can either be dependencies of platform modules or depend on platform modules.
A common module can depend only on other common modules and libraries, including the common version of the Kotlin standard library (kotlin-stdlib-common). Common modules contain only Kotlin code, and not code in any other languages.
A platform module can depend on any modules and libraries available on the given platform (including Java libraries in case of Kotlin/JVM and JS libraries for Kotlin/JS). Platform modules targeting Kotlin/JVM can also contain code in Java and other JVM languages.
(Force-pushed on 27 jan 2018, sorry about that)