Hi everyone, I have a question about dependency pr...
# multiplatform
u
Hi everyone, I have a question about dependency propagation in Kotlin Multiplatform. I have two modules: A and B. • Module A adds the Room library with implementation("androidx.roomroom runtime...") in commonMain. • Module B depends on A with implementation(project(":A")). My expectation: Since A uses implementation, Room should not be exposed to B. Therefore, B should not be able to reference Room classes unless A declares them with api or B adds Room explicitly. But what I see in practice: In commonMain, B can still use Room classes without adding the Room dependency. It looks like the dependency is leaking from A even though it’s declared as implementation. What’s interesting is that this only happens with commonMain dependencies. When the dependency is added in androidMain, it works as expected: B cannot see Room unless it declares it itself. Questions: • Is this behavior expected for commonMain dependencies? • Could this be an IDE/classpath leak rather than a stable Gradle contract? • What is the recommended way to avoid this and ensure B cannot accidentally depend on Room?
e
Are they both modules (A and B) in the shared module??? If so, it's normal because all dependencies declared in commonMain can be referenced in any module within the shared module.
thank you frog 1
u
@Excellence kawej Ah, I see — it was because they are inside the shared module! Thanks a lot for the clarificationkodee loving
e
hey, I have the same issue, what do you mean by "inside the shared module"? I have a CMP project where the composeApp depends on a
designsystem
module, which has a
material3
dependency, that I want to hide from the
composeApp
module, but it's still visible:
Copy code
# settings.gradle.kts
include(":composeApp")
include(":core:designsystem")
<...>

# :core:designsystem:build.gradle.kts
kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation(compose.material3)
        }
    }
}
<...>
Did you find a solution for this?
u
@Ernestas I wasn’t able to “fix” it either — I just came to understand that this is a characteristic of how KMP works. In a single KMP/shared module, the commonMain source set is shared by all code inside that module. So if you add a dependency (like material3) to commonMain of one sub-module, it will be visible to any other code in that same shared module.
e
Then this pretty much defeats the purpose of modularising 😄
u
I agree with you to some extent.🙏 But even if libraries are shared across commonMain, I don’t think modularisation is completely meaningless — it still makes sense in terms of separating logic and responsibilities. If you happen to find a solution or workaround for hiding dependencies in this setup, I’d really appreciate it if you could share it as well!
👍 1
e
In single module Android projects I have been using this as a workaround, if it's enough for you to hide the suggestions from autocompletion, then this might work:
Copy code
#.idea/codeInsightSettings.xml
<project version="4">
    <component name="JavaProjectCodeInsightSettings">
        <excluded-names>
            <name>androidx.compose.material3</name> <------ The import you want to exclude
        </excluded-names>
    </component>
</project>
But this will hide the import from all modules 🙂
e
@Ernestas not really because the composeApp as a shared module in which you can find three others module that share all the dependencies declared in commonMain.dependencies sourceSets. But when you have a module outside the composeApp or shared module, it cannot be accessed inside the shared module, however you can do the inverse thing, you should put the core module inside the shared module and call the shared module in the build.gradle.kts file of your androidApp like this :
Copy code
dependencies {
    ... //other dependencies
    implementation(project(":shared"))
}
Or you could just call the core:designSystem inside the commonMain.dependencies in the build.gradle.kts file of your shared module
Copy code
commonMain.dependencies {
    implementation(project(":core:designSystem"))
}
But depending on what i see, i could say that your core module is inside the shared module(composeApp). So why have you declare it in gradle settings? If not could you provide your file structure, this way we could help you more???
e
This is my project structure,
:composeApp
is the main module, while other modules are added as dependencies in
:composeApp
Copy code
commonMain.dependencies {
    implementation(projects.core.designsystem)
    implementation(projects.core.navigation)
    <...>
}
e
Can i see the structure of whole project ??? Just folders not files...
Do you also have a shared module inside core module???
e
Well this is pretty much the whole project, there's also an
iosApp
module and that's it.
core
is just a simple folder
e
And what about composeApp module, there isn’t a shared module inside???
e
Not sure what you mean by shared module, it's a KMP module with commonMain/androidMain/iosMain packages
e
Yes exactly...
You see like in config module there you have a shared module, haven’t you???