Kotlin 1.3-M2: new multiplatform projects model

— you don’t need to do that. All the artifacts have already proper .pom files, there is also no need to pack them together; that’s a correct state to have a separate library for each target.

A proper solution for such a goal is to publish steadily, part by part. Bintray supports artifacts upload into the repository with having their actual publishing as a separate step; Maven Central has staging repositories as well. In both cases, you may run N builds with a publication on all the involved hosts, so all the necessary platform-specific artifacts are uploaded to the repo, and then publish them.

Talking about the process of a composite library publication (such as having Windows and Linux parts in your example), it’s a good idea to get rid of duplicated artifacts publication in advance, on the host side, during the build process. The main candidates for such a cleanup are, for instance, JVM, JS or native targets which may be built anywhere, as well as the root publication in case if the metadata is enabled. To accomplish that, you may add a bit of special logic to the project build script; it should define what will be published for the build depending on the given build parameters. What you need to achieve is to make the duplicated publications to be actually published only once. As a possible solution, the corresponding publish tasks may be disabled by name:

project.tasks.withType(org.gradle.api.publish.maven.tasks.AbstractPublishToMaven).all { publishTask ->
    publishTask.onlyIf { task -> /* some condition based on the `task.publication` property */ }
}

You may take name from task.publication; publication names are the same as the corresponding target names. The root publication has kotlinMultiplatform name.

1 Like

Suppose I have a mpp module in a gradle build and I want to add jvm-only module in the same project that depends on mpp module. Is it possible to use regular kotlin plugin or I have to create an mpp build with java-only presets.

Another question: how to integrate jmh benchmarks? They does not seem to work with mpp out of the box.

There’s a feature request for that filed at https://youtrack.jetbrains.com/issue/KT-27059

Jake is active in this forum. Wohooo. Big fan. Looking forward to see your talk at KotlinConf.

In general, it should be possible, via implementation/api project dependency — then the corresponding platform part is mapped automatically unless there are several targets specified for a single platform (e.g. several JVM targets in the example). In case of ambiguity, there are some ways to solve it, but if it’s not urgent, I’d prefer to keep the answer a couple of days, since a proper documentation for this part is approaching right now.

Still, you may face some issues on the way, like this or that which @JakeWharton mentioned. So if something arises, you are welcome to submit a request to the tracker.

I am trying to use a library generated with the multiplatform plugin with a project using ‘kotlin-platform-native’ plugin.

Everything is compiled using 1.3.0-rc-131.

Is this possible at the moment? I keep getting the following error,

Unable to find a matching configuration of com.soywiz:klock-macosX64:0.48.0-SNAPSHOT:
- Configuration ‘macosX64-api’:
- Found artifactType ‘org.jetbrains.kotlin.klib’ but wasn’t required.
- Required org.gradle.native.debuggable ‘false’ but no value provided.
- Required org.gradle.native.kotlin.platform ‘macos_x64’ but no value provided.
- Required org.gradle.native.operatingSystem ‘osx’ but no value provided.
- Required org.gradle.native.optimized ‘true’ but no value provided.
- Found org.gradle.status ‘integration’ but wasn’t required.
- Required org.gradle.usage ‘java-api’ and found incompatible value ‘kotlin-api’.
- Required org.jetbrains.kotlin.native.target ‘macos_x64’ and found compatible value ‘macos_x64’.
- Required org.jetbrains.kotlin.platform.type ‘native’ and found compatible value ‘native’.
- Configuration ‘metadata-api’:
- Found artifactType ‘jar’ but wasn’t required.
- Required org.gradle.native.debuggable ‘false’ but no value provided.
- Required org.gradle.native.kotlin.platform ‘macos_x64’ but no value provided.
- Required org.gradle.native.operatingSystem ‘osx’ but no value provided.
- Required org.gradle.native.optimized ‘true’ but no value provided.
- Found org.gradle.status ‘integration’ but wasn’t required.
- Required org.gradle.usage ‘java-api’ and found incompatible value ‘kotlin-api’.
- Required org.jetbrains.kotlin.native.target ‘macos_x64’ but no value provided.
- Required org.jetbrains.kotlin.platform.type ‘native’ and found incompatible value ‘common’.

It is possible with a requirement of Gradle metadata to be enabled for both sides (enableFeaturePreview('GRADLE_METADATA') in settings.gradle). Note that Gradle metadata publishing is an experimental Gradle feature which is not guaranteed to be backward-compatible. Future Gradle versions may fail to resolve a dependency to a library published with current versions of Gradle metadata. Library authors are recommended to use it to publish experimental versions of the library alongside with the stable publishing mechanism.

In general, consider migrating the part with kotlin-platform-native plugin to the new model as well. It’s preferable since kotlin-platform-native plugin is a part of the old multiplatform model which became a dead-end of the development. You may get an idea of how the dependencies look like for such case by this example.

Well I have GRADLE_METADATA enabled. Is Android Studio expected to support the multiplatform plugin in the near future? That is the only thing that is holding me back from migrating.

Edit: after converting my project to use the multiplatform plugin, the project compiles with the same dependency. But still wondering when android studio multiplatform plugin support is expected?

Edit 2: I see that multiplatform plugin does work in android studio fairly well already. :+1:

Yes, Android Studio 3.2 already supports the new multiplatform model if you have the proper Kotlin plugin installed — currently it’s the latest available Kotlin 1.3-RC2 (1.3.0-rc-116).

In case of facing any issues there — you are more than welcome to submit it to the tracker :slight_smile:

Love the new multiplatform project model, but I’m running into a bit of an issue. I want to publish two artifacts for one of my projects, a common artifact at logkat-common and a jvm artifact at logkat-jvm. With the previous model, these two artifacts were generated when running a build. However, with the new model, there’s no way to enable a common target, so only logkat-jvm and a metadata jar logkat-metadata are generated. Thus, as far as I can tell, there’s no way to generate a common jar with the new model. Am I missing something, or has this just not been added to the new model yet?

What do you want to achieve by publishing common part separately?
Also, please take a look at the publishing section of the new multiplatform documentation, maybe it’ll make it clearer on how to publish and use the published libraries.

I’ll take another look at the docs and report back, it’s entirely possible that I missed something. Cheers!

So, I looked over the documentation, and there doesn’t seem to be anything I missed.

To answer your question, I intend to use logkat in another (also multiplatform) project of mine. Thus, I would use the common artifact in the second project’s common source set, and the jvm artifact in the second project’s jvm source set.

Then just specify the corresponding dependencies in the second project’s source sets, like it’s described here: logkat-metadata goes to the common part and logkat-jvm to the jvm one. Does it work for you?

Somehow I completely missed that, my apologies. I tested it out with the method you suggested, and it worked without a hitch. However, I did run into something that you guys might want to address-- the metadata publication does not inherit the root project’s groupId or version by default.

— that sounds like something went wrong there. I failed to reproduce it from scratch: having group and version specified in the common build.gradle like this:

group 'com.example'
version '0.0.1'

— I got the following set of artifacts for a lib called foo: com.example:foo-metadata:0.0.1, com.example:foo-jvm:0.0.1 — isn’t it the same for you? Can you share an example project or at least its configuration then?

Is there anything built in to run applications like the gradle application plugin does? I got an jvm, common, js web app that just needs to start the backend for things to work but I’m finding myself having to manually define the startup behavior with more detail than probably necessary. How would you go about building a fat jar for example?

Turns out that target.jvmWithJava works correctly with the application plugin. jvmWithJava is not mentioned in the main page docs. Also it seems that the js compilation doesn’t generate kotlin.js files that would normally be created with the kotlin2js plugin. I’m using kotlin 1.2.71

target.jvmWithJava isn’t supported actually and going to be removed in the future.
Also, please use the latest available Kotlin 1.3.* version (which is currently 1.3.0-rc-190) — as the topic name says, the new model is introduced in Kotlin 1.3. There is a bug at the documentation site, though, which recommends 1.2.71 version, but it’s going to be fixed soon.

As to JS configuration, please make sure it is configured properly since it indeed requires some additional set up for the proper files generation (which is general for JS part and not specific for the multiplatform, though). To get the idea, have a look at this and this examples.

@piacenti As an alternative to the unsupported jvmWithJava preset mentioned by @wild_lynx, you can also create a separate Kotlin/JVM module (with no kotlin-multiplatform plugin, just kotlin) that depends on the multiplatform module, then just apply the application plugin in that JVM module. The same, I think, should work for building a fat JAR, as the JVM dependencies of the multiplatform module will be available in the JVM module as well.