JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.88k stars 1.15k forks source link

Cannot run compose desktop application using IDEA gutter #3123

Open Walingar opened 1 year ago

Walingar commented 1 year ago

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:

Versions

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.

Walingar commented 1 year ago

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

NorbertSandor commented 1 year ago

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

NorbertSandor commented 1 year ago

Besides, none of my "Kotlin application" run configurations work, not only the Compose/Desktop related ones :(

sellmair commented 1 year ago

Ok, I reviewed the current Situation and created the following issue on YouTrack: https://youtrack.jetbrains.com/issue/KT-58660/KGP-import-KotlinRunConfiguration-wont-be-able-to-infer-correct-runtime-classpath

Generally, I take this issue very seriously. The proposal will hopefully fix more issues with unreliable run-gutters. Please let me know if you have any objections or suggestions for improvement.

conradboehnke commented 1 year ago

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 :)

sellmair commented 1 year ago

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

shalva97 commented 1 year ago

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

sellmair commented 1 year ago

I am very glad to hear this! @AlexeyTsvetkov I think this issue is resolved; At least from IntelliJ and Kotlin side. What do you think about closing it?

dima-avdeev-jb commented 1 year ago

@Walingar Can you please check on your side and close this issue?

shalva97 commented 1 year ago

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...

maiatoday commented 1 year ago

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.

DarkAtra commented 1 year ago

@AlexeyTsvetkov just ran into the same issue, can we reopen the ticket?

kotlin.version=1.9.0
compose.version=1.5.0
idea.version=IntelliJ IDEA 2023.2.1, Build #IU-232.9559.62, built on August 23, 2023
AlexeyTsvetkov commented 1 year ago

@DarkAtra I'm not sure it is actually the same issue. Could you please provide some additional information?

  1. What OS do you use?
  2. What Kotlin Gradle plugin is used in the module where you are seeing the issue? Is it org.jetbrains.kotlin.jvm or org.jetbrains.kotlin.multiplatform?
DarkAtra commented 1 year ago

@AlexeyTsvetkov the exception reads:

Exception in thread "main" java.lang.ExceptionInInitializerError
    at androidx.compose.ui.res.ImageResources_desktopKt.loadImageBitmap(ImageResources.desktop.kt:33)
        [...]
Caused by: org.jetbrains.skiko.LibraryLoadException: Cannot find libskiko-macos-arm64.dylib.sha256, proper native dependency missing.
    at org.jetbrains.skiko.Library.findAndLoad(Library.kt:105)
    at org.jetbrains.skiko.Library.load(Library.kt:59)

I tried on both Windows 10 and MacOS 13.5.1 (22G90) on an Apple M2 Pro Chip and got the same error message (with different os and arch). In my gradle setup, i use: kotlin("multiplatform") and id("org.jetbrains.compose") -> see: https://github.com/DarkAtra/bfme2-patcher/blob/compose-issue/updater/build.gradle.kts#L5-L6

Versions: https://github.com/DarkAtra/bfme2-patcher/blob/compose-issue/gradle.properties#L2-L3

wwalkingg commented 1 year ago

@AlexeyTsvetkov the exception reads:


Exception in thread "main" java.lang.ExceptionInInitializerError

  at androidx.compose.ui.res.ImageResources_desktopKt.loadImageBitmap(ImageResources.desktop.kt:33)

        [...]

Caused by: org.jetbrains.skiko.LibraryLoadException: Cannot find libskiko-macos-arm64.dylib.sha256, proper native dependency missing.

  at org.jetbrains.skiko.Library.findAndLoad(Library.kt:105)

  at org.jetbrains.skiko.Library.load(Library.kt:59)

I tried on both Windows 10 and MacOS 13.5.1 (22G90) on an Apple M2 Pro Chip and got the same error message (with different os and arch).

In my gradle setup, i use: kotlin("multiplatform") and id("org.jetbrains.compose") -> see: https://github.com/DarkAtra/bfme2-patcher/blob/compose-issue/updater/build.gradle.kts#L5-L6

Versions: https://github.com/DarkAtra/bfme2-patcher/blob/compose-issue/gradle.properties#L2-L3

Cradle sync firstly, then click the gutter in left of your app main function

DarkAtra commented 1 year ago

@wwalkingg while that works, it does not allow setting a working directory via the run configuration anymore (this is a blocker for me). What is the reason for switching to gradle jvmRun instead of whatever compose was using in previous versions?

AlexeyTsvetkov commented 1 year ago

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:

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

DarkAtra commented 1 year ago

@AlexeyTsvetkov ty for the detailed explanation! i'll try using jvm as i primarily target windows.

gandrewstone commented 1 year ago

I'm hitting this in multiplatform 1.9.0. I am doing multiplatform for both jvm and android (and other targets), so I had to roll my own jvm app jar because mp doesn't support jvm and android at the same time.

The workaround suggested here: https://github.com/JetBrains/compose-multiplatform/issues/3123#issuecomment-1647435023 (import a platform specific jar into the jvm project) works for me. But obviously its counter to the entire point of a JVM project which is to run on many platforms.

Any ideas about how/whether putting all the platform-specific jars into my app "fat" jar would work?

This is my jvm "fat jar creator" code:

/* Put all the dependent files into a single big jar */
tasks.register<Jar>("appJar") {
    archiveClassifier.set("app")
    manifest {
        attributes["Main-Class"] = "my.class.path"
    }
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE

    for (c in kotlin.targets.named("jvm").get().compilations)
    {
        val tmp = c.runtimeDependencyFiles
        if (tmp != null)
        {
            // If its a jar blow the jar up and add the class files in that jar
            from(tmp.filter { it.name.endsWith("jar") }.map { zipTree(it)})
        }
        from(c.output)
    }
}
AlexeyTsvetkov commented 1 year ago

I'm hitting this in multiplatform 1.9.0. I am doing multiplatform for both jvm and android (and other targets), so I had to roll my own jvm app jar because mp doesn't support jvm and android at the same time.

@gandrewstone I don't understand, what mp doesn't support jvm and android at the same time means? Kotlin Multiplatform does support both JVM and Android targets in the same project. It's even possible to create a shared JVM source set between Desktop JVM and Android (there might be some quirks with doing that, but Compose Multiplatform actually uses that to avoid duplicating code between Android and Desktop JVM).

luangs7 commented 1 year ago

still happens on Mac M1 Compose version = 1.5.1 Kotlin version = 1.9.10 plugin = multiplatform

if downgrade Kotlin version to 1.8.10 and Compose version to 1.3.1 it works.

wwalkingg commented 12 months ago

still happens on Mac M1

Compose version = 1.5.1

Kotlin version = 1.9.10

plugin = multiplatform

if downgrade Kotlin version to 1.8.10

and Compose version to 1.3.1 it works.

Try after gradle sync completely ?

luangs7 commented 12 months ago

still happens on Mac M1 Compose version = 1.5.1 Kotlin version = 1.9.10 plugin = multiplatform if downgrade Kotlin version to 1.8.10 and Compose version to 1.3.1 it works.

Try after gradle sync completely ?

yep, after a lot ones

pablichjenkov commented 12 months ago

@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.

sunny-chung commented 11 months ago

This issue appears after I upgrading my IDE from version 2022 to 2023, compose multiplatform from 1.3.0 to 1.5.2 and kotlin from 1.8.0 to 1.8.22. It disappears if I downgrade only kotlin back to 1.8.0.

Exception in thread "main" java.lang.ExceptionInInitializerError
    at androidx.compose.ui.awt.WindowComposeBridge.<init>(WindowComposeBridge.desktop.kt:40)
    at androidx.compose.ui.awt.ComposeWindowDelegate.<init>(ComposeWindowDelegate.desktop.kt:53)
    at androidx.compose.ui.awt.ComposeWindow.<init>(ComposeWindow.desktop.kt:62)
    at androidx.compose.ui.awt.ComposeWindow.<init>(ComposeWindow.desktop.kt:60)
    at androidx.compose.ui.window.Window_desktopKt$Window$3.invoke(Window.desktop.kt:179)
    at androidx.compose.ui.window.Window_desktopKt$Window$3.invoke(Window.desktop.kt:173)
    at androidx.compose.ui.window.Window_desktopKt$Window$10.invoke(Window.desktop.kt:405)
    at androidx.compose.ui.window.Window_desktopKt$Window$10.invoke(Window.desktop.kt:402)
    at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$2.invoke(AwtWindow.desktop.kt:74)
    at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$2.invoke(AwtWindow.desktop.kt:73)
    at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:81)
    at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:1137)
    at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:828)
    at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:849)
    at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1041)
    at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:520)
    at androidx.compose.ui.window.Application_desktopKt$awaitApplication$2$1$2.invokeSuspend(Application.desktop.kt:219)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: org.jetbrains.skiko.LibraryLoadException: Cannot find libskiko-macos-arm64.dylib.sha256, proper native dependency missing.
    at org.jetbrains.skiko.Library.findAndLoad(Library.kt:105)
    at org.jetbrains.skiko.Library.load(Library.kt:59)
    at org.jetbrains.skiko.SkiaLayer.<clinit>(SkiaLayer.awt.kt:32)
    ... 32 more

I am using the Compose Multiplatform template generated by InteiiJ IDEA, and then manually updated the versions. The content of gradle.properties is as follow:

kotlin.code.style=official
kotlin.version=1.8.22
agp.version=7.3.0
compose.version=1.5.2
instabeejeongeun commented 11 months ago

I also had the same issue but updating the versions like below and run command(./gradlew run) in the terminal fixed the issue.

kotlin.version=1.9.0 compose.version=1.5.0-beta01

Exception in thread "main" java.lang.ExceptionInInitializerError
...
Caused by: org.jetbrains.skiko.LibraryLoadException: Cannot find libskiko-macos-arm64.dylib.sha256, proper native dependency missing.
maiatoday commented 11 months ago

ah no running ./gradlew run always works for me, it is only the green play button that doesn't

nantoka69 commented 10 months ago

The issue with the non-working green play button just appeared in my current Jetpack Compose Multiplatform project. It happened after I upgraded to the latest Kotlin plugin but as I import the compose libraries without version version numbers it could be as well that it was just something else that updated silently.

I use currently

After trying everything that I read here and in other sources about the problem I came up with the following solution:

That way I got at least a working green play button and can wait until some upgrades solve the problem.

dima-avdeev-jb commented 10 months ago

@nantoka69 What Operatin system do you have?

nantoka69 commented 10 months ago

Windows 10 Pro

dima-avdeev-jb commented 10 months ago

@nantoka69 Can you please provide a minimal reproducible sample? And we will try to check it on Windows too.

sellmair commented 9 months ago

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

philburk commented 6 months ago

I had the same problem on Mac. I used the latest IDEA and a project downloaded from the Wizard. I could not build it after an hours of work so I think the MultiPlatform feature is just not ready for prime time.

STEPS

IntelliJ IDEA 2023.3.4 (Community Edition)
Build #IC-233.14475.28, built on February 12, 2024
Runtime version: 17.0.10+1-b1087.17 x86_64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
macOS 14.2.1
GC: G1 Young Generation, G1 Old Generation
Memory: 2048M
Cores: 16
Metal Rendering is ON
Kotlin: 233.14475.28-IJ

EXPECTED Hello world window.

ACTUAL Caused by: org.jetbrains.skiko.LibraryLoadException: Cannot find libskiko-macos-x64.dylib.sha256, proper native dependency missing.

I tried going into Settings>>Build>>Compiler and change Kotlin compiler to 1.8.22. But then I got errors related to Android SDK 34 license and it asked me to run "sdkmanager.bat", on a Mac! So I switched back to the bundled 1.9.22 compiler.

I then went back to the Wizard and remove Android as a target and repeated the previous steps. This time I got a bunch of errors related to not finding "KotlinProject". Maybe I messed it up by renaming the project folder.

So I chnged the name to TestMultiPlatform in the Wizard. Download a project for Desktop and Web. Opened it in IDEA and now I am getting a ton of build errors like:

settings.gradle.kts:1:1: error: unresolved reference: rootProject
rootProject.name = "TestMultiPlatform"

settings.gradle.kts:1:13: error: variable expected
rootProject.name = "TestMultiPlatform"

I started over and created a Fresh project called KotlinProject. I removed the old broken project from Recents. Now I am back to the original libskiko error!

If I type: ./gradlew run in the project folder then it builds and runs.

philburk commented 6 months ago

I tried the suggestion from nantoka69 above but it did not work using "desktop:run" on MacBook. So I modified them slightly and the following worked.

okushnikov commented 2 weeks ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.