Kotlin 1.3-M2: new multiplatform projects model

Are you able to share your project? I will then compare

Here it is: GitHub - wild-lynx/mpp-lib-dependency: A sample chain of two multiplatform libraries and JVM app (app --dependsOn-> lib2 --dependsOn-> lib1)

https://github.com/wild-lynx/mpp-lib-dependency/pull/1

Seems to be something to do with the intellij plugin as I had to add it to reproduce the error

Is there a way to use in a specific module some common code imported from a third party library which has not been compiled for the platform you need?

Let me clarify my use case. I’m writing a library to handle graph data structures, in Kotlin of course, using only the common module. Now, I want to publish it without any specific target platform so that wherever you will need to use it, the code should be compatible. This may overcome the Kotlin Native host compilation requirements.

Firstly I tried without any preset and the library is only available in the common module, even if imported in a, say, JVM module.
Then I figured out that the build system compiles and prepare the artifacts for each specified preset so I added a JVM module and a JS one, published it and they work flawlessly on their respective platforms. Now, i’m working on a Winows machine but Jitpack builds only on Linux. How could I overcome this?

Is there a way to use in a specific module some common code imported from a third party library which has not been compiled for the platform you need?

The library has to be compiled for all the required targets, there is no way to generate just a standalone common or, in other words, platform-agnostic library and then customize its platform targets separately. So you are absolutely right: build system compiles and prepares the artifacts for each specified preset.

Now, i’m working on a Winows machine but Jitpack builds only on Linux. How could I overcome this?

You may use Docker image with Kotlin/Native and Java inside. My colleague may help you to prepare one and to put it to the Docker Hub, if needed. The image openjdk:8 already has OpenJDK 8 inside. Then goes something like this: docker run --rm -it ubuntu:16.04 bash

Another option is to use WSL :slight_smile:

May I ask if there will be the possibility to do so? It would be very handy and can brilliantly solve some of the native multi-platform building issues in my opinion.

I would love to but I have no knowledge yet about Docker and serious CI. Moreover, I have not figured out how I can locally create artifacts and then publish them oven some maven repo.

So if i am not mistaken, at the moment there is no way to publish in one single place all the artifacts unless I build all the possible artifacts on the various systems and then pack them together and publish them somewhere. Is there a guide for that?

1 Like

Thank you, now I reproduced it either.
The root cause is this. While there is an immediate workaround for a similar configuration with a project dependency, it’s unclear yet if there is something to do in the same way for the library dependency. Except for a PR there with the configuration update, though :slight_smile:
Anyway, thank you for the report, my colleagues are already aware now and I’ll let you know if some workaround for your case comes by either.

There is no plan yet, but you are welcome to submit a feature request for that.

Yes, so far the recommended way for a multiplatform library with incompatible Kotlin/Native parts (in terms of host-target correspondence) is to set up the publication from different systems into the one place. A feature request here is welcome too.

I was able to correctly build for Linux using WSL. Can you please show how to pack the output and publish it on a Maven repo?

Speaking about Docker.

On Windows, you may instead consider using Windows Subsystem for Linux (WSL), which actually gives you a locally running Linux on your Windows machine. It may be easier to use, all you need is to install Open JDK 1.8 via the package manager

Speaking about Docker. First, you need to install it. You need Docker for Mac or Docker for Windows, depending on your OS. Check out the Docker website for details. Developers - Docker
Docker is essentially a way to start a specific Linux image on your machine. Quite similar to what you have in the Windows Subsystem for Linux, but better for any CI or automation.

Once you have Docker installed you may run the console command like that to have the build task executed in the container.

docker run -v <YOUR PROJECT DIR>:/build -it java:8 /build/gradlew build

The -v command argument mounts the <YOUR PROJECT DIR> into the Linux to the /build path. There you call the /build/gradlew build command. You need to have Gradle Wrapper to make it work. That is the standard way to use Gradle build system. Every time you run the command a fresh machine is started. Any changes are lost when the command is completed.

For local development, you may start a container with bash command. That is the way to preserve the state of a machine between runs.

Should you miss any specific packages, you may check to use Dockerfile to create your own image for Docker. You may see the Dockerfile reference | Docker Documentation for more details.

I managed to do it and it worked flawlessly :slight_smile: Now that I have the build/ folder with all the outputs, how do I assemble them in an artifact and publish them?

What is the right place to submit a feature request?

Please use https://youtrack.jetbrains.com and select Kotlin project there

You shall be able to see all folders and all your disks from the WSL. Check out stackowerflow question for the topic. In that case, you will have another path, not build/.

The best way to assemble the project is to prepare a build script. Most likely it will be the Gradle build that does it. The rest is to execute the script under Linux to get the binaries.

With the command wsl is even easier, directly from the terminal from IntelliJ IDEA you can just type:

wsl ./gradlew build

and it builds under the default WSL directly in the build/ folder of the project. I was trying to create an Exec task that runs the command at the end of the build but no success so far.

Now, which is the correct way to pack the build/ and publish it manually somewhere?

Ok thanks - another solution is to get the intellij gradle plugin to support implementation/api - "implementation" dependencies don't get bundled into the distribution zip · Issue #239 · JetBrains/gradle-intellij-plugin · GitHub

I am facing another issue that is my JS kotlinOptions seem to be ignored (they work with the old mpp)

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
    kotlinOptions {
        sourceMap = true
        sourceMapEmbedSources = "always"
        moduleKind = "commonjs"
        outputFile = "out.js"
    }
}

The k-new-mpp-samples doesn’t appear to have an example of using these options either

Now, which is the correct way to pack the build/ and publish it manually somewhere?

Is the way described here not suitable for you?

Sure. Also, I’m happy to say that the issue is going to be fixed in the upcoming release of Kotlin plugin, most probably Kotlin 1.3-RC2.

Are you able to do it like this?

tasks.withType(compileKotlinJs.getClass()) {
    kotlinOptions {
        moduleKind = "umd"
        sourceMap = true
        metaInfo = true
    }
}

(the example is taken from here, it might be useful for a further tune of JS part to be able to run tests)

Also, can you try if such kind configuration works for you?

kotlin {
    targets {
        /* ... */
        fromPreset(presets.js, 'js')

        configure([js]) {
            tasks.getByName(compilations.main.compileKotlinTaskName).kotlinOptions {
                sourceMap = true
                sourceMapEmbedSources = "always"
                moduleKind = "commonjs"
                outputFile = "out.js"
            }
        }
    }
    /* ... */
}

Yes that works, thanks again.

Now I have a question which is related to the question from @lamba92

My library is a Kotlin wrapper around RX using rxJava on the JVM and rxJS on JS. I include my dependency on rxJava here: https://github.com/TeamHubApp/RxKotlinMultiplatform/blob/master/build.gradle#L60

But obviously I can’t include my dependency on rxJS in the JS target as its an npm module.

How is it recommended we distribute such libraries for JS platforms? Create a node package which consumers of the library will need to include in their package.json for their JS product?

Yes, right now the best way to distribute libraries for JS (including Kotlin/JS) is NPM.
To create own library you need to turn on generating mata.js files and would be better to switch moduleKind to ‘umd’, also, optionally you can turn on generating sourcemaps to allow debug generated JS files using .kt files, like:

compileKotlin2Js {
    //...
    kotlinOptions.metaInfo = true
    kotlinOptions.moduleKind = 'umd'
    kotlinOptions.sourceMap = true // optional
}

Also, kotlin-frontend-plugin could be useful to depend on other libraries from NPM.

1 Like

Hey, just letting you know that Kotlin 1.3-RC2 (1.3.0-rc-116) has been released and the issue should go away now :slight_smile:

1 Like

I want to publish in a dependency all artifacts built from Linux and Windows (eventually MacOS, Hackintosh may help :joy:). Since I cannot build all artifacts with a “single” build, I first need to gather all the compiled stuff from the build/ folder, then pack them in some way, build the right .pom and publish it (hopefully not manually).

Notice that I may be missing some basic knowledges on how to publish a library since I’ve always used Jitpack + maven publish plugin to automate the whole process, eventually writing only few lines to pack documentation as well. If i do, please just give me few keywords and I’ll Google them before continuing the discussion.

Thank you again for the patience :slight_smile: