Kotlin 1.3-M2: new multiplatform projects model

I believe there are some problems with Android configuration which aren’t actually related to MPP. To find out the root issue, try some additional logging, described here — stack traces will help you to get the idea what’s actually wrong with that. So far, it’s hard to diagnose what is the problem, not enough information for that.

As to shadow plugin (com.github.johnrengelman.shadow), the situation is as follows.

  • in case of using jvmWithJava target, it should work as is, just apply it from the top level of the build.gradle script. Note, hovewer, that the target is going to be deprecated as it’s already said above.

  • when using with jvm target, an additional task definition is needed, like the following:

      task shadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
              def target = kotlin.targets.jvm6
              from target.compilations.main.output
              def runtimeClasspath = target.compilations.main.runtimeDependencyFiles
              configurations = [runtimeClasspath]
      }
    

    — where jvm6 is the JVM target’s name.

    So overall build.gradle will look like:

      group 'com.example'
      version '1.0'
    
      buildscript {
          repositories {
              jcenter()
          }
          dependencies {
              classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.10'
              classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.2'
          }
      }
    
      apply plugin: 'kotlin-multiplatform'
      apply plugin: 'com.github.johnrengelman.shadow'
    
      repositories {
          jcenter()
      }
    
      kotlin {
          targets {
              fromPreset(presets.jvm, 'jvm6')
          }
          sourceSets {
              commonMain {
                  dependencies {
                      api 'org.jetbrains.kotlin:kotlin-stdlib-common'
                  }
              }
              jvm6Main {
                  dependencies {
                      api 'org.jetbrains.kotlin:kotlin-stdlib'
                  }
              }
          }
      }
    
      task shadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
      	from kotlin.targets.jvm6.compilations.main.output
      	def runtimeClasspath = kotlin.targets.jvm6.compilations.main.runtimeDependencyFiles
      	configurations = [runtimeClasspath]
    

The support of kotlin-frontend plugin for JS is in progress right now, you may track the progress via this issue.

1 Like

Generated a stack trace, saved to
https://scans.gradle.com/s/kckuuohn2u23q/console-log
For now, got it working by hooking my task onto compileDebugSources

That specific task did not work, but with your idea of using a specific task found compileDebugSources which does work

thank you for reply, i’m tried shadow plugin in this way:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
    }
}

plugins {
    id 'kotlin-multiplatform' version '1.3.10'
    id 'kotlinx-serialization' version '1.3.10'
}

apply plugin: 'com.github.johnrengelman.shadow'

repositories {
    jcenter()
    mavenCentral()
    maven { url "https://dl.bintray.com/kotlin/ktor" }
    maven { url "https://kotlin.bintray.com/kotlinx" }
    maven { url "http://dl.bintray.com/kotlin/kotlin-eap" }
    maven { url "http://dl.bintray.com/kotlin/kotlin-js-wrappers" }
}

kotlin {
    ext.ktor_version = '1.0.0-beta-4'
    ext.serialization_version = '0.9.0'

    targets {
        fromPreset(presets.jvm, 'jvm')
        fromPreset(presets.js, 'js')
    }
    sourceSets {
        commonMain {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
                implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version"
            }
        }
        commonTest {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-test-common'
                implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
            }
        }
        jvmMain {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
                implementation 'org.jetbrains.exposed:exposed:0.9.1'
                implementation "io.ktor:ktor-server-netty:$ktor_version"
                implementation "io.ktor:ktor-gson:$ktor_version"
                implementation "io.ktor:ktor-client-core:$ktor_version"
                implementation "io.ktor:ktor-client-cio:$ktor_version"
                implementation "io.ktor:ktor-locations:$ktor_version"
                implementation "io.ktor:ktor-html-builder:$ktor_version"
                implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"
                implementation "mysql:mysql-connector-java:8.0.7-dmr"
            }
        }
        jvmTest {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-test'
                implementation 'org.jetbrains.kotlin:kotlin-test-junit'
            }
        }
        jsMain {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-stdlib-js'
                implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version"
                implementation 'org.jetbrains:kotlin-react:16.6.0-pre.59-kotlin-1.3.0'
                implementation 'org.jetbrains:kotlin-react-dom:16.6.0-pre.59-kotlin-1.3.0'
            }
        }
        jsTest {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-test-js'
            }
        }
    }
}

task shadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
    def target = kotlin.targets.jvm
    from target.compilations.main.output
    def runtimeClasspath = target.compilations.main.runtimeDependencyFiles
    configurations = [runtimeClasspath]
    println "task shadow jar"
}

it builds but jar is not fat…

@leonid
I tried your build script, and by running ./gradlew shadowJar I got a fat JAR under build/libs/test-project.jar which contains the dependencies:

$ unzip build/libs/test-project.jar
$ tree build/libs/test-project -L 2 -d
.
├── com
│   ├── google
│   ├── mysql
│   └── typesafe
├── io
│   ├── ktor
│   └── netty
├── junit
│   ├── extensions
│   ├── framework
│   ├── runner
│   └── textui
├── kotlin
│   ├── annotation
│   ├── collections
│   ├── comparisons
│   ├── concurrent
│   ├── contracts
│   ├── coroutines
│   ├── experimental
│   ├── internal
│   ├── io
│   ├── jdk7
│   ├── js
│   ├── jvm
│   ├── math
│   ├── properties
│   ├── random
│   ├── ranges
│   ├── reflect
│   ├── sequences
│   ├── streams
│   ├── system
│   └── text
├── kotlinx
│   ├── atomicfu
│   ├── coroutines
│   ├── html
│   ├── io
│   └── serialization
├── META-INF
│   ├── maven
│   ├── proguard
│   └── services
└── org
    ├── eclipse
    ├── hamcrest
    ├── intellij
    ├── jetbrains
    ├── joda
    ├── json
    ├── junit
    └── slf4j

Is your result different? What do you mean by ‘jar is not fat’?

1 Like

@leonid Note that the shadow JAR is created alongside with the normal JAR for the JVM target. The normal JAR is suffixed with -jvm. It is up to you to replace the normal JVM JAR with the fat one whenever it is used or published.

1 Like

yes, it works, thank you

You guys should really add this to documentation.

1 Like

@wild_lynx Hi, I’ve tried creating a project from template (Kotlin - Mobile Android and iOS) in Idea 2018.3.1, kotlin plugin 1.3.11-release-IJ2018.3-1, gradle 4.7. I’ve tried adding jvm target for ktor server I planned and building that target throws this error Error:Kotlin: Unsupported plugin option: org.jetbrains.kotlin.android:enabled=true.
Looking at module setting, it appears that all targets/submodules/sourcesets have android plugin enabled in “Compiler Plugins” tab. I’ve tried removing that in .idea project files but it just reappears after IDE restart. Any suggestions? build.gradle.xml (3.1 KB)

It would be good to have, or may it already exist, an example for new mpp model, like kotlin-fullstack-example https://github.com/Kotlin/kotlin-fullstack-sample/issues/27

Please make sure in IDE that Preferences | Build, Execution, Deployment | Build Tools | Gradle | Runner > Delegate IDE build/run actions to gradle is checked. For the IDEA’s built-in builder (JPS), there is an issue. Does it help?

Also please note that in general, Gradle is a preferred way to build the multiplatform projects; JPS has certain limitations (in particular, it wouldn’t build any of Native targets, such as iOS in your project).

A small comment on the build.gradle you’ve shared: for the source sets generated from the presets (jvm, js, etc.), it isn’t necessary to specify explicitly the dependencies of the corresponding *Main and *Test compilations on commonMain and commonTest explicitly, those are specified already by default, as it said at the documentation. So the following line of your configuration for serverMain may be simply removed: dependsOn commonMain

Indeed, there are some already. You may try various samples generated by IDEA via New Project Wizard: open Kotlin section, there are four of them (Multiplatform).

Also, please have a look:
https://github.com/orangy/multiplatform-lib
https://github.com/h0tk3y/better-parse
https://github.com/Kotlin/kotlinx.atomicfu
https://github.com/JetBrains/kotlin-mpp-example
https://github.com/JetBrains/kotlinconf-app
https://github.com/jonnyzzz/kotlin-fractals
https://github.com/jonnyzzz/kotlin-mpp-mobile
https://github.com/RubyLichtenstein/Kotlin-Multiplatform-Firebase

Thanks, offloading build to gradle fixed the build issues. Btw, should jvm server be runnable from IDEA now? Cause I’m having troubles just running hello world server, I get this error: Error: Could not find or load main class rs.mmitic.MainKt

It’s possible that I’m just a dummy, I haven’t coded in Kotlin that much but I’ve tried lots of stuff:

package rs.mmitic
import sample.hello

object Main {
    @JvmStatic
    fun main(args: Array<String>) {
        print(hello())
    }
}

class Main2 {
    companion object {
        @JvmStatic
        fun main(vararg args: String) {}
    }
}

fun main(args: Array<String>) {
    print(hello())
}

There is an issue with main run in IDEA for the multiplatform projects having Android target among others.

As a workaround, a Gradle task for the main run may be specified:

task run(type: JavaExec) {
    main = 'sample.SampleJKt'
    def target = kotlin.targets.jvm
    def compilation = target.compilations.main

    def classes = files(
            compilation.runtimeDependencyFiles,
            compilation.output.allOutputs
    )
    classpath = classes
}

— where main is a path to the class with main() function defined as follows:

  • if main is declared as a top-level function, then packageName + “.” + fileName.capitalized().removeSuffix(".kt") + “Kt”
  • if main is declared inside of an object, then packageName + “.” + objectName

For a file without package, for example, ActualB.kt: main = 'ActualBKt'

Thanks a lot.

Is it going to be the only way to work around the absence of jvmWithJava? In Okio, we’ve got unit tests written in Java living in the JVM module: their main value is that they test the API from the perspective of a Java user of the library and help us keep the API Java-friendly. Some unit tests rely on internal members, hence moving them into a separate module is not an option. Inability to compile and run Java code in the JVM module is pretty inconvenient and will require a lot of redesign on our part.

1 Like

@Egorand Yes, for now. But we are going to introduce Java support in the future releases, in some form. From what I can say now, it will likely be something quite similar to jvmWithJava, because applying the java Gradle plugin seems to be the only way to reach compatibility with existing 3rd-party plugins that work with Java. So if you try to use jvmWithJava, then your feedback is welcome. The issue for Java support that you can follow is: KT-26256.

Thanks! Here’s an issue I filed a couple days ago: https://youtrack.jetbrains.com/issue/KT-28985

Doesn’t look like the plugin plays well with Dokka, and it’s not mentioned on the official docs page. Is Dokka gonna be supported eventually?