compose-multiplatform icon indicating copy to clipboard operation
compose-multiplatform copied to clipboard

Failing to use Compose runtime in common code targeting native

Open kirillzh opened this issue 2 years ago • 14 comments

Failing to compile simple Compose function targeting native code (iOS iosX64 or iosArm64).

Kotlin 1.7.10 Jetbrains Compose 1.2.0-beta01 Compose compiler 1.3.0

Repo code is in this branch: https://github.com/kirillzh/kmm-production-sample/tree/common-compose.

// shared/src/commonMain
@Composable
fun Foo() {
}

Error:

> Task :shared:linkDebugFrameworkIosSimulatorArm64 FAILED
w: Mimalloc allocator isn't supported on target ios_simulator_arm64. Used standard mode.
e: Compilation failed: No file for com.github.jetbrains.rssreader/Foo|4071909078632269291[0] (@ com.github.jetbrains.rssreader/Foo|4071909078632269291[0]) in module `<RssReader:shared>`[ModuleDescriptorImpl@57d43629]

 * Source files: 
 * Compiler version info: Konan: 1.7.10 / Kotlin: 1.7.20
 * Output kind: FRAMEWORK

e: java.lang.IllegalStateException: No file for com.github.jetbrains.rssreader/Foo|4071909078632269291[0] (@ com.github.jetbrains.rssreader/Foo|4071909078632269291[0]) in module `<RssReader:shared>`[ModuleDescriptorImpl@57d43629]
	at org.jetbrains.kotlin.backend.common.serialization.BasicIrModuleDeserializer.deserializeIrSymbol(BasicIrModuleDeserializer.kt:95)
Full Error
> Task :shared:linkDebugFrameworkIosSimulatorArm64 FAILED
w: Mimalloc allocator isn't supported on target ios_simulator_arm64. Used standard mode.
e: Compilation failed: No file for com.github.jetbrains.rssreader/Foo|4071909078632269291[0] (@ com.github.jetbrains.rssreader/Foo|4071909078632269291[0]) in module `<RssReader:shared>`[ModuleDescriptorImpl@57d43629]

 * Source files: 
 * Compiler version info: Konan: 1.7.10 / Kotlin: 1.7.20
 * Output kind: FRAMEWORK

e: java.lang.IllegalStateException: No file for com.github.jetbrains.rssreader/Foo|4071909078632269291[0] (@ com.github.jetbrains.rssreader/Foo|4071909078632269291[0]) in module `<RssReader:shared>`[ModuleDescriptorImpl@57d43629]
	at org.jetbrains.kotlin.backend.common.serialization.BasicIrModuleDeserializer.deserializeIrSymbol(BasicIrModuleDeserializer.kt:95)
	at org.jetbrains.kotlin.backend.common.serialization.IrModuleDeserializer.declareIrSymbol(IrModuleDeserializer.kt:74)
	at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.findDeserializedDeclarationForSymbol(KotlinIrLinker.kt:127)
	at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.deserializeOrResolveDeclaration(KotlinIrLinker.kt:169)
	at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.getDeclaration(KotlinIrLinker.kt:158)
	at org.jetbrains.kotlin.ir.util.ExternalDependenciesGeneratorKt.getDeclaration(ExternalDependenciesGenerator.kt:57)
	at org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator.generateUnboundSymbolsAsDependencies(ExternalDependenciesGenerator.kt:44)
	at org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator.generateUnboundSymbolsAsDependencies(ModuleGenerator.kt:52)
	at org.jetbrains.kotlin.psi2ir.Psi2IrTranslator.generateModuleFragment(Psi2IrTranslator.kt:92)
	at org.jetbrains.kotlin.psi2ir.Psi2IrTranslator.generateModuleFragment$default(Psi2IrTranslator.kt:75)
	at org.jetbrains.kotlin.backend.konan.PsiToIrKt.psiToIr(PsiToIr.kt:187)
	at org.jetbrains.kotlin.backend.konan.ToplevelPhasesKt$psiToIrPhase$1.invoke(ToplevelPhases.kt:120)
	at org.jetbrains.kotlin.backend.konan.ToplevelPhasesKt$psiToIrPhase$1.invoke(ToplevelPhases.kt:118)
	at org.jetbrains.kotlin.backend.common.phaser.PhaseBuildersKt$namedOpUnitPhase$1.invoke(PhaseBuilders.kt:96)
	at org.jetbrains.kotlin.backend.common.phaser.PhaseBuildersKt$namedOpUnitPhase$1.invoke(PhaseBuilders.kt:94)
	at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.invoke(CompilerPhase.kt:96)
	at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:29)
	at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.invoke(CompilerPhase.kt:96)
	at org.jetbrains.kotlin.backend.common.phaser.CompilerPhaseKt.invokeToplevel(CompilerPhase.kt:43)
	at org.jetbrains.kotlin.backend.konan.KonanDriverKt.runTopLevelPhases(KonanDriver.kt:40)
	at org.jetbrains.kotlin.cli.bc.K2Native.doExecute(K2Native.kt:94)

Moving Composable function under a class/interface, gives a bit different error:

// shared/src/commonMain
interface Example {
  @Composable
  fun Foo() {
  }
}

Error:

e: java.lang.AssertionError: Unbound symbols not allowed

Unbound public symbol IrSimpleFunctionPublicSymbolImpl: com.github.jetbrains.rssreader/Example.Foo|4071909078632269291[0]
	at org.jetbrains.kotlin.ir.util.SymbolTableKt.noUnboundLeft(SymbolTable.kt:1141)
	at org.jetbrains.kotlin.psi2ir.Psi2IrTranslator.generateModuleFragment(Psi2IrTranslator.kt:96)
	at org.jetbrains.kotlin.psi2ir.Psi2IrTranslator.generateModuleFragment$default(Psi2IrTranslator.kt:75)
	at org.jetbrains.kotlin.backend.konan.PsiToIrKt.psiToIr(PsiToIr.kt:187)
	at org.jetbrains.kotlin.backend.konan.ToplevelPhasesKt$psiToIrPhase$1.invoke(ToplevelPhases.kt:120)
	at org.jetbrains.kotlin.backend.konan.ToplevelPhasesKt$psiToIrPhase$1.invoke(ToplevelPhases.kt:118)
	at org.jetbrains.kotlin.backend.common.phaser.PhaseBuildersKt$namedOpUnitPhase$1.invoke(PhaseBuilders.kt:96)
	at org.jetbrains.kotlin.backend.common.phaser.PhaseBuildersKt$namedOpUnitPhase$1.invoke(PhaseBuilders.kt:94)
	at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.invoke(CompilerPhase.kt:96)

kirillzh avatar Sep 29 '22 05:09 kirillzh

Possible related to https://github.com/JetBrains/compose-jb/issues/2342

DjakaTechnology avatar Oct 08 '22 09:10 DjakaTechnology

I'm getting the exact same issue. Just adding @Composable is bringing this error

gregriggins36 avatar Nov 08 '22 23:11 gregriggins36

Can you please try version 1.3.0-alpha01-dev849

and add to gradle.properties: kotlin.native.cacheKind=none

dima-avdeev-jb avatar Nov 13 '22 14:11 dima-avdeev-jb

I'm getting the exact same issue. Just adding @Composable is bringing this error

I fixed my issue by making the @Composable function internal 🤦‍♂️

gregriggins36 avatar Nov 14 '22 11:11 gregriggins36

Maybe relates with https://github.com/JetBrains/compose-jb/issues/2386 and https://github.com/JetBrains/compose-jb/issues/2342

dima-avdeev-jb avatar Nov 28 '22 09:11 dima-avdeev-jb

I'm also getting this issue, which was also fixed by marking my composable internal!

kevincianfarini avatar Nov 30 '22 21:11 kevincianfarini

@dima-avdeev-jb, I'm understanding that it's not currently possible to make a Composable function public in common code while targeting native.

This is blocking us from being able to modularize the code with Composables, and most importantly being able to incrementally migrate Android logic into shared code base incrementally.

Is there a fix for this in some dev release, and if not, would you have an estimate for when this is planned to be fixed?

kirillzh avatar Jan 13 '23 05:01 kirillzh

@kirillzh Yes, you can't use public Composable functions in iOS for now. But, you can use internal functions.

dima-avdeev-jb avatar Jan 13 '23 05:01 dima-avdeev-jb

@kirillzh Except for the composable function of the module finally used in iOS, it is okay to use the public composable function.

For example, I use feature-wise modular like below

graph TD;
A[feature1] --> |Public Composable function| C[presentation]
B[feature2] --> |Public Composable function| C
C --> |Internal Composable function| D[iosApp]

In this case, public composable functions in feature1 and feature2 are available.

TaehoonLeee avatar Jan 13 '23 06:01 TaehoonLeee

Hi @TaehoonLeee, could you share a simple example of what you described. I tried on my side and still no way to expose a Composable in iOS target. This feature is important since many organizations would want to have a shared-ui library, made of components that other iOS projects consume as Composables, not as UIViewControllers.

pablichjenkov avatar Jan 26 '23 09:01 pablichjenkov

@pablichjenkov

It is impossible to use composable functions directly on iOS target. Therefore, all the composable functions in the module exported to the iOS target must be specified as internal.

However, the composable functions in other modules may be public. Using this point, it seems possible to modularize composable function.

https://github.com/TaehoonLeee/multi-module-clean-architecture/tree/multi-platform

In above project the iOS app uses presentation module only. So the composable functions written in the presentation module should be internal. And the others in the other modules are can be public.

My English is limited. I ask for your understanding.

TaehoonLeee avatar Jan 27 '23 00:01 TaehoonLeee

@TaehoonLeee , Don't worry about the English mine is probably worst. I believe now I understand better what you explained before, and you are right, the only module affected is the last one used in the iOS interoperability. Saying so, the issue can really be categorized as minor. Thank you so much for your help. It could be really beneficial to document this behavior somewhere. When you get the error the first time, it makes you think that Composables cannot be public in libraries and that is not correct at all. It is only the last library consumed by the iosApp the one enforcing the internal constraint and only for ios target.

pablichjenkov avatar Jan 27 '23 01:01 pablichjenkov

Do we know if this is resolved by compose compiler 1.4.0 and Kotlin 1.8.20? I'm seeing similar mentions in other related issues such as https://github.com/JetBrains/compose-multiplatform/issues/2901#issuecomment-1504894914

kevincianfarini avatar Apr 20 '23 17:04 kevincianfarini

Do we know if this is resolved by compose compiler 1.4.0 and Kotlin 1.8.20? I'm seeing similar mentions in other related issues such as https://github.com/JetBrains/compose-multiplatform/issues/2901#issuecomment-1504894914

Yeup, got fixed in 1.4.0

pablichjenkov avatar Apr 20 '23 17:04 pablichjenkov

Wohoo!

kevincianfarini avatar Apr 20 '23 18:04 kevincianfarini

Fixed in Compose 1.4.0

dima-avdeev-jb avatar Apr 26 '23 06:04 dima-avdeev-jb

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

okushnikov avatar Jul 14 '24 16:07 okushnikov