compose-multiplatform: Cannot run compose desktop application using IDEA gutter

Describe the bug When I have a multiplatform Compose project with desktop target, I try to run app with IDEA gutter icon and it fails in runtime with exceptions like:

Cannot find libskiko-macos-arm64.dylib.sha256, proper native dependency missing.

When use Gradle :run everything works fine but really slow, comparing with IDEA start.

If I use only jvm target, not multiplatform, starting from gutter works fine as well.

Affected platforms Select one of the platforms below:

  • Desktop (in multiplatform setup)

Versions

  • Kotlin version*: 1.8.20
  • Compose Multiplatform version*: 1.4.0
  • OS version: MacOS X
  • OS architecture: arm64
  • JDK (for desktop issues): corretto-17

To Reproduce

  1. Open image viewer example in IDEA
  2. Try to run desktop main from IDEA gutter

Result: it runs, but fails with exceptions like:

Cannot find libskiko-macos-arm64.dylib.sha256, proper native dependency missing.

Expected behavior Should work fine.

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Reactions: 5
  • Comments: 34 (5 by maintainers)

Most upvoted comments

This may be a little late, but I had this issue too a while ago. So I looked into the documentation of Skiko itself and found out that they suggest manually importing it the following way (the “version” may differ):

val osName = System.getProperty("os.name")
    val targetOs = when {
        osName == "Mac OS X" -> "macos"
        osName.startsWith("Win") -> "windows"
        osName.startsWith("Linux") -> "linux"
        else -> error("Unsupported OS: $osName")
    }

    val targetArch = when (val osArch = System.getProperty("os.arch")) {
        "x86_64", "amd64" -> "x64"
        "aarch64" -> "arm64"
        else -> error("Unsupported arch: $osArch")
    }

    val version = "0.7.70" // or any more recent version
    val target = "${targetOs}-${targetArch}"

    sourceSets {
        val jvmMain by getting {
            dependencies {
                implementation("org.jetbrains.skiko:skiko-awt-runtime-$target:$version")
                implementation(compose.desktop.currentOs)
           }
      }
}

I simply put this into the following:

kotlin {}

but I think this also works when you just put it outside of it. But the implementation has to be in the ‘dependencies {}’ of course 😄 . This solution solved the problem perfectly for me. I also tried to change ‘implementation(compose.desktop.currentOs)’ to ‘implementation(compose.desktop.macos_arm64)’ but it didn’t fix it for me. Hope this helps 😃

Please upgrade IntelliJ and Kotlin instead and report back if this works for you 👍

I have spent lots of time on this, but at least it works with Kotlin 1.9.0, compose 1.5.0-beta01 and Intellij 2023.2

I updated intellij and used Kotlin 1.9.0, compose 1.5.0-beta01 and Intellij 2023.2 on a desktop only compose project and I am still getting the missing skiko error. I fixed it using the manual import as described in the above comment So for me this is still an issue when I try to run from the gutter.

@luangs7 try uninstalling the compose multiplatform plugin in AS/IJ and install it again. Or even better uninstall the plugin, install a more recent IDE version and install the plugin again. Also after uninstalling the plugin, make sure it is removed from the directory AS/IJ saves the plugins, just in case.

I’ve just run into this issue on Windows.

I used the “play” button to run the app which causes the error:

Caused by: org.jetbrains.skiko.LibraryLoadException: Cannot find skiko-windows-x64.dll.sha256, proper native dependency missing.

Executing the compose desktop/run Gradle task directly works.

The “play” button also works if I remove the

kotlin.mpp.import.enableKgpDependencyResolution=true

line from gradle.properties. (But I cannot do that because my goal is to reevaluate Gradle included builds with multiplatform projects, which feature should theoretically work in Kotlin 1.8.20 but needs this setting.)

Related conversation: https://kotlinlang.slack.com/archives/C01D6HTPATV/p1683708168775229

There is still an issue on Android Studio; Root cause is that AS does not import Gradle task data and the execution relies on this data being present. The Kotlin Build Tools team is aware of this, right now.

https://youtrack.jetbrains.com/issue/KTIJ-27797/Android-Studio-Support-Multiplatform-jvm-run-carrier-task

What is the reason for switching to gradle jvmRun instead of whatever compose was used in previous versions?

@DarkAtra we (Compose Multiplatform team) did not change anything in regards to this issue.

Some time ago, the Kotlin Multiplatform team had implemented a new, better, faster import. The new import did not consider that IntelliJ was bypassing Gradle when running applications, even if build/test actions are delegated to Gradle. When a user clicked the “run” icon in the gutter, IntelliJ would delegate the build itself, but then ran the application directly using run configuration settings and dependencies it resolved during the last import.

IntelliJ’s default run mechanism is not very intuitive to both end users and Kotlin project developers. For example, even with the old KMP import, IntelliJ could discover a new runtime dependency only during re-import.

However, the new KMP import completely ignored runtime and runtimeOnly dependencies, because they are not needed for editing/refactoring/navigation and etc. At the same time, Compose’s bindings to Skia (the native rendering library) are naturally runtime only dependencies:

  • the native bindings have to be built for each platform separately;
  • the bindings are quite big to put all platform DLLs into the same jar;
  • and the rendering library should be considered an implementation detail anyway (we don’t provide any compatibility guarantees for Skiko, all compatibility guarantees are for Compose public APIs only).

When the original issue with run from the gutter was uncovered, the new import was already enabled by default. To fix the issue, the Kotlin Multiplatform team has swiftly implemented a new run mechanism, which uses Gradle for both building and running code.

As a workaround, you can try to set the working directory in the build script:

tasks.configureEach {
    if (name == "jvmRun") {
        this as JavaExec
        setWorkingDir(<A_DESIRED_BUILD_DIRECTORY>)
    }
}

The old running mechanism still works for non-multiplatform modules. As long as your project does not target Android/iOS/WASM, you can try to use org.jetbrains.kotlin.jvm instead of org.jetbrains.kotlin.multiplatform Gradle plugin.

Also, feel free to send feedback to the Kotlin Multiplatform team directly by creating an issue at https://youtrack.jetbrains.com/issues/KTIJ

One small thing to note, the old broken run configuration still persists(it has Kotlin icon), the new run config has Gradle icon and works. I was manually selecting it and was like not again…

I investigated the issue a little bit and found that skiko loads libraries manually here

And Compose Gradle plugin provides all necessary resources, but when running from IDEA doesn’t.

I don’t know why it works fine with jvm only cases (without kotlin(“mutliplatform”) only kotlin(“jvm”)). Only noticed that with “jvm” plugin skiko-awt-runtime is provided as a runtime dependency but with “multiplatform” it is not