Hi everyone! :wave: I’m working on a Kotlin/Nativ...
# kotlin-native
r
Hi everyone! 👋 I’m working on a Kotlin/Native project that generates bindings for GObject libraries. The bindings’ API is platform-specific, meaning the API differs slightly between Linux and macOS. However, I’d like to publish these bindings as a single artifact (same artifact ID) on MavenCentral to simplify consumption for users of my library. Here’s how I’m setting up my targets in the
kotlin
block:
Copy code
import org.gradle.internal.os.OperatingSystem

kotlin {
    val hostOs = OperatingSystem.current()
    val hostArch = System.getProperty("os.arch")
    val isArm64 = hostArch == "aarch64"
    
    when {
        hostOs.isLinux && !isArm64 -> linuxX64()
        hostOs.isMacOsX && isArm64 -> macosArm64()
        else -> throw GradleException("Host OS '${hostOs}' is not supported by this project.")
    }
}
I’ve tried the following so far: 1. Built the artifacts on Linux and published them to MavenLocal. The Linux bindings work fine when consumed. 2. Did the same for macOS (built on macOS and published to MavenLocal), and it also works fine on macOS. 3. Merged the artifacts by copying the macOS ones into the same directory as the Linux ones and overwriting the
*.module
and
*.pom
files. However, this breaks the Linux target when I try to consume it:
Copy code
Could not resolve all files for configuration ':linuxX64CompileKlibraries'.
   Could not resolve org.gtkkn:gtk4:0.0.1-SNAPSHOT.
   No matching variant of org.gtkkn:gtk4:0.0.1-SNAPSHOT was found.
   ...
From what I understand, the problem arises because the
*.module
file gets overwritten, and it no longer includes the
linuxX64
variant when the macOS artifacts are added. This makes me worried that the same issue will occur if I publish to MavenCentral without resolving this. Does anyone have experience with this kind of multiplatform publishing? Is there a way to merge or aggregate the
*.module
metadata from the builds on Linux and macOS? Or should I take a different approach entirely? Thanks in advance for any advice or insights!
Since my last message, I’ve explored enabling all target variants in the
kotlin
block (e.g.,
linuxX64
and
macosArm64
) simultaneously, instead of dynamically enabling one target based on the host OS. Issues with Multiple Targets 1. CInterop Definitions Conflict: • When enabling multiple targets, the
nativeMain
source set no longer builds. This happens because cinterop
.def
files are managed per specific target. 2. CInterop Commonization: • Enabling
kotlin.mpp.enableCInteropCommonization=true
results in missing native functions on Linux. For example, functions like
g_module_build_path
and
g_module_close
are no longer available in the generated bindings. • I suspect this happen because Kotlin/Native parses headers in a "common" environment for all platforms. Platform-specific macros or conditional
#ifdef
blocks (e.g., in
gmodule.h
) might exclude these functions. 3. Why Duplicating Bindings Doesn’t Work: • Moving away from
nativeMain
and duplicating bindings for each target is not feasible due to the complexity of the library. • A lot of shared code in
nativeMain
depends on native functions (e.g.,
g_free
and
g_type_interfaces
). • It also uses type aliases (e.g.,
GType
) and generated bindings classes (e.g.,
GLib
and
GObject
). If I move away from
nativeMain
, I would need to duplicate all this code for each platform, which is not maintainable. What are my options for handling this scenario?
e
• I suspect this happen because Kotlin/Native parses headers in a "common" environment for all platforms.
I suspect it's more likely that you don't have macos headers available on the linux runner, while the macos runner has the linux sysroot headers available
r
Mmm but
g_module_build_path
and
g_module_close
are available on Linux, and they are found if I target only linux, why the missing macos headers would remove these 2 but not others from the same gmodule library?
e
something in the glib headers includes a system header and then fails?
r
maybe, I could do some test on mac to se if there I have similar issue, but still I must be able to build on linux, since the gir files that I use to generate the bindings are platform specific and I can't really build all the artifacts from macos using crosscompilation (I think)
to be able to crosscompile everything form mac (assuming that it's even doable for this project) I would have to collect all the headers for all the dependencies for both platform, I assume it would be quite difficult to do, if compared to using the host package manager, or am I missing something?
e
https://youtrack.jetbrains.com/issue/KT-74073/Improve-cross-compilation-with-cinterops it's not really supported now anyhow so it may take some experimentation to figure out how to get the header setup right
but I would expect the actual target libraries are needed for linking to the right symbols, as that's how cross-compilation works for other native languages
r
so, as far as you know, for now I have to release separate artifacts per target variant, like I'm currently doing: • https://s01.oss.sonatype.org/content/repositories/snapshots/org/gtkkn/gtk4-linuxx64/https://s01.oss.sonatype.org/content/repositories/snapshots/org/gtkkn/gtk4-macosarm64/ as in right now there is no way to provide a single artifact for these bindings for that supports both linux and mac, without manually merging them and manually uploading them to maven, is this correct?
e
it may be possible to manually set up the headers and libraries for cross-compilation, I just don't know of any example outside of stdlib which is probably special
👍 1
b
just out of curiosity, @Roberto Leinardi, is your work related to https://gitlab.com/gtk-kt/gtk-kt?
r
hi @Bruno Medeiros, it is related in the meaning that both project try to achieve the same goal: K/N bindings for GTK, but gtk-kt is afaik abandoned and the bindings were manually written, which is unmaintainable, while gtk-kn is now actively maintained again (after a period of inactivity) and the bindings are generated using GObject Introspection (GIR), which allows to generate theoretically bindings for every library providing valid
.gir
files. gtk-kt readme actively redirects to gtk-kn: > NOTE It is suggested to look at gtk-kn a possible successor project. https://gitlab.com/gtk-kt/gtk-kt#gtk-kt
b
got it, good work! I think Kotlin/Native is one of the most underrated pieces of tech, so noce to se it evolving :)
r
thanks, btw if you want to give the project a try, check the get started page: https://gtk-kn.org/get-started/ it is not production ready (I'm still dealing with GObject memory management and some essential bindings are missing) but I would love some early feedback
Hey @ephemient, I'm facing a pretty strange issue that feels like a bug of the multiplatform plugin: on both Linux and macOS, the published artifacts work correctly (the application builds and runs fine), however, on macOS, the IDE (IntelliJ IDEA) does not detect the library properly when added as a dependency from Maven Local or Maven Central. After investigating the artifact files, I noticed that only on macOS, Gradle generates an additional
-metadata.jar
file (e.g.,
adwaita-macosarm64-0.0.3a-SNAPSHOT-metadata.jar
), which is completely empty except for the META-INF directory. This file seems to be breaking IDEA’s dependency resolution: if I manually delete it, the IDE correctly recognizes the library again. I've tried: • Removing the
metadata
publication from
publishing.publications
• Disabling tasks that publish
metadata
Both approaches result in Gradle failing during the publication process. To publish the artifacts I'm specifically calling the task for macOS, and not the generic umbrella task:
publishMacosArm64PublicationToMavenLocal
Do you have any advice on how to properly prevent this empty
-metadata.jar
from being generated? Also, where would be the best place to report this as a bug?